tech@mandoc.bsd.lv
 help / color / mirror / Atom feed
* [PATCH docbook2mdoc] Add NODE_EMAIL
@ 2019-03-22 10:33 Stephen Gregoratto
  2019-03-22 12:32 ` Ingo Schwarze
  2019-03-22 20:07 ` Ingo Schwarze
  0 siblings, 2 replies; 7+ messages in thread
From: Stephen Gregoratto @ 2019-03-22 10:33 UTC (permalink / raw)
  To: tech

Add support for the <email> node. The official XSL stylesheets enclose 
the address in angle brackets, and so shall we. While we're at it, add a 
missing return statement for NODE_REFENTRYTITLE.

I intend to add more nodes in the future so I'm starting with a small 
addition to get a feel of the code-base. Critique is fully welcome here.
I hope to add <author> node soon, so we can generate a full `.An` block.
For example:

  <author>
    <personname>
      <firstname>Joe</firstname>
      <othername>Bloggo</othername>
      <surname>Bloggs</surname>
    </personname>
    <email>joe@foo.net</email>
  </author>

Would transform into:

  .An Joe So Bloggo Sq Bloggs Aq Mt joe@foo.net

The othername part may be overkill right now. Not sure if this would 
require it's own function like pnode_printrefsect().

Index: docbook2mdoc.c
===================================================================
RCS file: /cvs/docbook2mdoc/docbook2mdoc.c,v
retrieving revision 1.47
diff -u -p -r1.47 docbook2mdoc.c
--- docbook2mdoc.c	8 Mar 2019 15:18:50 -0000	1.47
+++ docbook2mdoc.c	22 Mar 2019 10:07:15 -0000
@@ -105,6 +105,7 @@ static	const struct node nodes[NODE__MAX
 	{ "constant", 0 },
 	{ "copyright", NODE_IGNTEXT },
 	{ "date", 0 },
+	{ "email", 0 },
 	{ "emphasis", 0 },
 	{ "entry", 0 },
 	{ "envar", 0 },
@@ -1252,6 +1253,10 @@ pnode_print(struct parse *p, struct pnod
 		pnode_printmopen(p);
 		fputs("Dv", stdout);
 		break;
+	case (NODE_EMAIL):
+		pnode_printmopen(p);
+		fputs("Aq Mt", stdout);
+		break;
 	case (NODE_EMPHASIS):
 		pnode_printmopen(p);
 		fputs("Em", stdout);
@@ -1522,6 +1527,7 @@ pnode_print(struct parse *p, struct pnod
 	case (NODE_CODE):
 	case (NODE_COMMAND):
 	case (NODE_CONSTANT):
+	case (NODE_EMAIL):
 	case (NODE_EMPHASIS):
 	case (NODE_ENVAR):
 	case (NODE_FILENAME):
Index: extern.h
===================================================================
RCS file: /cvs/docbook2mdoc/extern.h,v
retrieving revision 1.25
diff -u -p -r1.25 extern.h
--- extern.h	19 Mar 2015 10:04:32 -0000	1.25
+++ extern.h	22 Mar 2019 10:07:15 -0000
@@ -20,6 +20,7 @@ enum	nodeid {
 	NODE_CONSTANT,
 	NODE_COPYRIGHT,
 	NODE_DATE,
+	NODE_EMAIL,
 	NODE_EMPHASIS,
 	NODE_ENTRY,
 	NODE_ENVAR,
Index: rules.c
===================================================================
RCS file: /cvs/docbook2mdoc/rules.c,v
retrieving revision 1.25
diff -u -p -r1.25 rules.c
--- rules.c	19 Mar 2015 10:04:32 -0000	1.25
+++ rules.c	22 Mar 2019 10:07:15 -0000
@@ -71,6 +71,7 @@ isparent(enum nodeid node, enum nodeid p
 		return(0);
 	case (NODE_ACRONYM):
 		switch (parent) {
+		case (NODE_EMAIL):
 		case (NODE_EMPHASIS):
 		case (NODE_ENTRY):
 		case (NODE_FUNCSYNOPSISINFO):
@@ -289,6 +290,7 @@ isparent(enum nodeid node, enum nodeid p
 		return(0);
 	case (NODE_DATE):
 		switch (parent) {
+		case (NODE_EMAIL):
 		case (NODE_EMPHASIS):
 		case (NODE_ENTRY):
 		case (NODE_FUNCSYNOPSISINFO):
@@ -311,8 +313,30 @@ isparent(enum nodeid node, enum nodeid p
 			break;
 		}
 		return(0);
+	case (NODE_EMAIL):
+		switch (parent) {
+		case (NODE_ENTRY):
+		case (NODE_FUNCSYNOPSISINFO):
+		case (NODE_LINK):
+		case (NODE_PARA):
+		case (NODE_PROGRAMLISTING):
+		case (NODE_REFDESCRIPTOR):
+		case (NODE_REFENTRYTITLE):
+		case (NODE_REFNAME):
+		case (NODE_REFPURPOSE):
+		case (NODE_SCREEN):
+		case (NODE_SYNOPSIS):
+		case (NODE_TERM):
+		case (NODE_TITLE):
+		case (NODE_USERINPUT):
+			return(1);
+		default:
+			break;
+		}
+		return(0);
 	case (NODE_EMPHASIS):
 		switch (parent) {
+		case (NODE_EMAIL):
 		case (NODE_EMPHASIS):
 		case (NODE_ENTRY):
 		case (NODE_FUNCSYNOPSISINFO):
@@ -577,6 +601,7 @@ isparent(enum nodeid node, enum nodeid p
 		case (NODE_CODE):
 		case (NODE_COMMAND):
 		case (NODE_CONSTANT):
+		case (NODE_EMAIL):
 		case (NODE_EMPHASIS):
 		case (NODE_ENTRY):
 		case (NODE_ENVAR):
@@ -883,6 +908,7 @@ isparent(enum nodeid node, enum nodeid p
 		return(0);
 	case (NODE_QUOTE):
 		switch (parent) {
+		case (NODE_EMAIL):
 		case (NODE_EMPHASIS):
 		case (NODE_ENTRY):
 		case (NODE_FUNCSYNOPSISINFO):
@@ -920,6 +946,7 @@ isparent(enum nodeid node, enum nodeid p
 		default:
 			break;
 		}
+		return(0);
 	case (NODE_REFMETA):
 		return(parent == NODE_REFENTRY);
 	case (NODE_REFMETAINFO):
@@ -966,6 +993,7 @@ isparent(enum nodeid node, enum nodeid p
 		case (NODE_COMMAND):
 		case (NODE_CONSTANT):
 		case (NODE_EMPHASIS):
+		case (NODE_EMAIL):
 		case (NODE_ENTRY):
 		case (NODE_ENVAR):
 		case (NODE_FILENAME):
@@ -1208,6 +1236,7 @@ isparent(enum nodeid node, enum nodeid p
 	case (NODE_TRADEMARK):
 		switch (parent) {
 		case (NODE_ACRONYM):
+		case (NODE_EMAIL):
 		case (NODE_EMPHASIS):
 		case (NODE_ENTRY):
 		case (NODE_FUNCSYNOPSISINFO):
@@ -1350,6 +1379,7 @@ isparent(enum nodeid node, enum nodeid p
 		return(0);
 	case (NODE_WORDASWORD):
 		switch (parent) {
+		case (NODE_EMAIL):
 		case (NODE_EMPHASIS):
 		case (NODE_ENTRY):
 		case (NODE_FUNCSYNOPSISINFO):
--
 To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH docbook2mdoc] Add NODE_EMAIL
  2019-03-22 10:33 [PATCH docbook2mdoc] Add NODE_EMAIL Stephen Gregoratto
@ 2019-03-22 12:32 ` Ingo Schwarze
  2019-03-22 20:07 ` Ingo Schwarze
  1 sibling, 0 replies; 7+ messages in thread
From: Ingo Schwarze @ 2019-03-22 12:32 UTC (permalink / raw)
  To: kristaps; +Cc: tech, Stephen Gregoratto

Hello Kristaps,

i sent you the following questions some time ago and didn't hear
back.  I seriously need feedback or development of docbook2mdoc(1)
cannot make progress.  For example, the patch sent by Stephen is
massively conflicting with my changes.  I would love to first commit
my changes, then adapt and commit Stephen's patch.  It looks like
we have a chance to gain another docbook2mdoc(1) developer, which
would be really great.  So please tell me whether you are OK with
the direction, and with me moving ahead without asking an OK for
every single patch.

Thanks,
  Ingo


 ----- 8< ----- schnipp ----- >8 ----- 8< ----- schnapp ----- >8 -----

 *** Here is my plan which i need feedback on: ***

i did some more work on docbook2mdoc(1) and now i'm able to format,
for example, /usr/xenocara/proto/xorgproto/specs/sect1-9.xml
though it's certainly not pretty yet.

To make progress, i'd really like to commit my changes rather than
juggling local patches, so i'm asking for permission to do these
major structural changes and then go ahead with more, smaller
improvements as they may be needed.  Of course, i'll commit everything
in logical steps, not as one large hump.  What i need to do right
now is:

 1. Drop the useless DocBook XML validation,
    both isparent() and NODE_IGNTEXT,
    see my older mail below for a more detailed rationale.
    This allows a critical speedup of development and substantial
    simplification of the code without any downside whatsoever.

 2. Provide a mechanism to map multiple node names to the same node ID.
    This is needed because the DocBook language is extremely redundant.
    Having different NODE_* enum constants for all the synonymous
    nodes would result in big switch statements with many cases
    all over the place; mapping them together allows short, simple
    if statements instead.
    This requirement is simply a consequence of the DocBook language
    being so horribly ill-designed.

The following patch also contains:

 3. New code to extract the .Dt name
    from the id attribute of the root node.
 4. New code to automatically detect header levels (Sh, Ss, Pp Sy)
    rather than hardcoding XML node names to specific levels.
    Some documents have parts and chapters, some don't, so static
    mappings simply don't work.
 5. New code to avoid printing .Pp right after .Sh and .Ss.
 6. NODE_ITEMIZEDLIST is .Bl -bullet, not .Bl -item.
 7. Many new DocBook node types.

The cumulative patch currently is -1529 +303 lines of code (!!)
and makes the program significantly more powerful and vastly easier
to maintain and extend.

Of course, i'd also like to switch to OpenBSD KNF:
 * const == var   ->   var == const
 * return(irc);   ->   return irc;
 * case (const):  ->   case const:
but if you dislike that, i can stick to the current style;
please just mention whether you are OK with applying KNF.

 *** Stephen's patch follows after my patch ***


Index: README
===================================================================
RCS file: /home/cvs/mdocml/docbook2mdoc/README,v
retrieving revision 1.2
diff -u -p -r1.2 README
--- README	8 Mar 2019 10:13:12 -0000	1.2
+++ README	9 Mar 2019 13:53:42 -0000
@@ -14,25 +14,6 @@ For these, you will have to look at 4.5 
 
 Add the alpha-ordered node (NODE_FOO) to extern.h.
 
-Next, add rules.c isparent() rule.  This is the hard part.  First,
-create a top-level switch statement for NODE_FOO.  Create a white-list
-of switch cases beneath that corresponding to each "These elements
-contain foo":
-
- switch (parent) {
- case (NODE_BAR):
- case (NODE_BAZ):
-  return(1);
- default:
-  break;
- }
- return(0);
-
-Next, go through the "The following elements occur in foo" and add a
-"case (NODE_FOO)" to each of those elements' switches.
-
-Now the hard work is finished!
-
 Next, add the name and whether it admits text to docbook2mdoc.c's
 "nodes" structure array.
 
Index: docbook2mdoc.c
===================================================================
RCS file: /home/cvs/mdocml/docbook2mdoc/docbook2mdoc.c,v
retrieving revision 1.47
diff -u -p -r1.47 docbook2mdoc.c
--- docbook2mdoc.c	8 Mar 2019 15:18:50 -0000	1.47
+++ docbook2mdoc.c	9 Mar 2019 13:53:43 -0000
@@ -44,13 +44,13 @@ struct	parse {
 	char		*b; /* NUL-terminated buffer for pre-print */
 	size_t		 bsz; /* current length of b */
 	size_t		 mbsz; /* max bsz allocation */
+	int		 level; /* header level, starting at 1 */
 	int		 newln; /* output: are we on a fresh line */
 };
 
 struct	node {
 	const char	*name; /* docbook element name */
-	unsigned int	 flags;
-#define	NODE_IGNTEXT	 1 /* ignore all contained text */
+	enum nodeid	 node; /* docbook element to generate */
 };
 
 TAILQ_HEAD(pnodeq, pnode);
@@ -90,103 +90,136 @@ static	const char *attrvals[ATTRVAL__MAX
 	"req"
 };
 
-static	const struct node nodes[NODE__MAX] = {
-	{ NULL, 0 },
-	{ "acronym", 0 },
-	{ "anchor", NODE_IGNTEXT },
-	{ "application", 0 },
-	{ "arg", 0 },
-	{ "caution", NODE_IGNTEXT },
-	{ "citerefentry", NODE_IGNTEXT },
-	{ "cmdsynopsis", NODE_IGNTEXT },
-	{ "code", 0 },
-	{ "colspec", NODE_IGNTEXT },
-	{ "command", 0 },
-	{ "constant", 0 },
-	{ "copyright", NODE_IGNTEXT },
-	{ "date", 0 },
-	{ "emphasis", 0 },
-	{ "entry", 0 },
-	{ "envar", 0 },
-	{ "fieldsynopsis", NODE_IGNTEXT },
-	{ "filename", 0 },
-	{ "funcdef", 0 },
-	{ "funcprototype", NODE_IGNTEXT },
-	{ "funcsynopsis", NODE_IGNTEXT },
-	{ "funcsynopsisinfo", 0 },
-	{ "function", 0 },
-	{ "group", NODE_IGNTEXT },
-	{ "holder", NODE_IGNTEXT },
-	{ "info", NODE_IGNTEXT },
-	{ "informalequation", NODE_IGNTEXT },
-	{ "informaltable", NODE_IGNTEXT },
-	{ "inlineequation", NODE_IGNTEXT },
-	{ "itemizedlist", NODE_IGNTEXT },
-	{ "link", 0 },
-	{ "listitem", NODE_IGNTEXT },
-	{ "literal", 0 },
-	{ "manvolnum", 0 },
-	{ "mml:math", NODE_IGNTEXT },
-	{ "mml:mfenced", 0 },
-	{ "mml:mfrac", 0 },
-	{ "mml:mi", 0 },
-	{ "mml:mn", 0 },
-	{ "mml:mo", 0 },
-	{ "mml:mrow", 0 },
-	{ "mml:msub", 0 },
-	{ "mml:msup", 0 },
-	{ "modifier", 0 },
-	{ "note", NODE_IGNTEXT },
-	{ "option", 0 },
-	{ "orderedlist", NODE_IGNTEXT },
-	{ "para", 0 },
-	{ "paramdef", 0 },
-	{ "parameter", 0 },
-	{ "programlisting", 0 },
-	{ "prompt", 0 },
-	{ "quote", 0 },
-	{ "refclass", NODE_IGNTEXT },
-	{ "refdescriptor", NODE_IGNTEXT },
-	{ "refentry", NODE_IGNTEXT },
-	{ "refentryinfo", NODE_IGNTEXT },
-	{ "refentrytitle", 0 },
-	{ "refmeta", NODE_IGNTEXT },
-	{ "refmetainfo", NODE_IGNTEXT },
-	{ "refmiscinfo", NODE_IGNTEXT },
-	{ "refname", 0 },
-	{ "refnamediv", NODE_IGNTEXT },
-	{ "refpurpose", 0 },
-	{ "refsect1", NODE_IGNTEXT },
-	{ "refsect2", NODE_IGNTEXT },
-	{ "refsect3", NODE_IGNTEXT },
-	{ "refsection", NODE_IGNTEXT },
-	{ "refsynopsisdiv", NODE_IGNTEXT },
-	{ "replaceable", 0 },
-	{ "row", NODE_IGNTEXT },
-	{ "sbr", NODE_IGNTEXT },
-	{ "screen", NODE_IGNTEXT },
-	{ "sgmltag", 0 },
-	{ "structname", 0 },
-	{ "synopsis", 0 },
-	{ "table", NODE_IGNTEXT },
-	{ "tbody", NODE_IGNTEXT },
-	{ "term", 0 },
-	{ NULL, 0 },
-	{ "tfoot", NODE_IGNTEXT },
-	{ "tgroup", NODE_IGNTEXT },
-	{ "thead", NODE_IGNTEXT },
-	{ "tip", NODE_IGNTEXT },
-	{ "title", 0 },
-	{ "trademark", 0 },
-	{ "type", 0 },
-	{ "ulink", 0 },
-	{ "userinput", 0 },
-	{ "variablelist", NODE_IGNTEXT },
-	{ "varlistentry", NODE_IGNTEXT },
-	{ "varname", 0 },
-	{ "warning", NODE_IGNTEXT },
-	{ "wordasword", 0 },
-	{ "year", NODE_IGNTEXT },
+static	const struct node nodes[] = {
+	{ "acronym",		NODE_ACRONYM },
+	{ "affiliation",	NODE_AFFILIATION },
+	{ "anchor",		NODE_ANCHOR },
+	{ "application",	NODE_APPLICATION },
+	{ "arg",		NODE_ARG },
+	{ "author",		NODE_AUTHOR },
+	{ "authorgroup",	NODE_AUTHORGROUP },
+	{ "blockquote",		NODE_BLOCKQUOTE },
+	{ "book",		NODE_BOOK },
+	{ "bookinfo",		NODE_BOOKINFO },
+	{ "caution",		NODE_CAUTION },
+	{ "chapter",		NODE_SECTION },
+	{ "citerefentry",	NODE_CITEREFENTRY },
+	{ "citetitle",		NODE_CITETITLE },
+	{ "cmdsynopsis",	NODE_CMDSYNOPSIS },
+	{ "code",		NODE_CODE },
+	{ "colspec",		NODE_COLSPEC },
+	{ "command",		NODE_COMMAND },
+	{ "constant",		NODE_CONSTANT },
+	{ "copyright",		NODE_COPYRIGHT },
+	{ "date",		NODE_DATE },
+	{ "editor",		NODE_EDITOR },
+	{ "emphasis",		NODE_EMPHASIS },
+	{ "entry",		NODE_ENTRY },
+	{ "envar",		NODE_ENVAR },
+	{ "fieldsynopsis",	NODE_FIELDSYNOPSIS },
+	{ "filename",		NODE_FILENAME },
+	{ "firstname",		NODE_FIRSTNAME },
+	{ "firstterm",		NODE_FIRSTTERM },
+	{ "footnote",		NODE_FOOTNOTE },
+	{ "funcdef",		NODE_FUNCDEF },
+	{ "funcprototype",	NODE_FUNCPROTOTYPE },
+	{ "funcsynopsis",	NODE_FUNCSYNOPSIS },
+	{ "funcsynopsisinfo",	NODE_FUNCSYNOPSISINFO },
+	{ "function",		NODE_FUNCTION },
+	{ "glossterm",		NODE_GLOSSTERM },
+	{ "group",		NODE_GROUP },
+	{ "holder",		NODE_HOLDER },
+	{ "index",		NODE_INDEX },
+	{ "indexterm",		NODE_INDEXTERM },
+	{ "info",		NODE_INFO },
+	{ "informalequation",	NODE_INFORMALEQUATION },
+	{ "informaltable",	NODE_INFORMALTABLE },
+	{ "inlineequation",	NODE_INLINEEQUATION },
+	{ "itemizedlist",	NODE_ITEMIZEDLIST },
+	{ "keysym",		NODE_KEYSYM },
+	{ "legalnotice",	NODE_LEGALNOTICE },
+	{ "link",		NODE_LINK },
+	{ "listitem",		NODE_LISTITEM },
+	{ "literal",		NODE_LITERAL },
+	{ "literallayout",	NODE_LITERALLAYOUT },
+	{ "manvolnum",		NODE_MANVOLNUM },
+	{ "member",		NODE_MEMBER },
+	{ "mml:math",		NODE_MML_MATH },
+	{ "mml:mfenced",	NODE_MML_MFENCED },
+	{ "mml:mfrac",		NODE_MML_MFRAC },
+	{ "mml:mi",		NODE_MML_MI },
+	{ "mml:mn",		NODE_MML_MN },
+	{ "mml:mo",		NODE_MML_MO },
+	{ "mml:mrow",		NODE_MML_MROW },
+	{ "mml:msub",		NODE_MML_MSUB },
+	{ "mml:msup",		NODE_MML_MSUP },
+	{ "modifier",		NODE_MODIFIER },
+	{ "note",		NODE_NOTE },
+	{ "option",		NODE_OPTION },
+	{ "orderedlist",	NODE_ORDEREDLIST },
+	{ "orgname",		NODE_ORGNAME },
+	{ "othername",		NODE_OTHERNAME },
+	{ "para",		NODE_PARA },
+	{ "paramdef",		NODE_PARAMDEF },
+	{ "parameter",		NODE_PARAMETER },
+	{ "part",		NODE_SECTION },
+	{ "phrase",		NODE_PHRASE },
+	{ "preface",		NODE_PREFACE },
+	{ "primary",		NODE_PRIMARY },
+	{ "programlisting",	NODE_PROGRAMLISTING },
+	{ "prompt",		NODE_PROMPT },
+	{ "quote",		NODE_QUOTE },
+	{ "refclass",		NODE_REFCLASS },
+	{ "refdescriptor",	NODE_REFDESCRIPTOR },
+	{ "refentry",		NODE_REFENTRY },
+	{ "refentryinfo",	NODE_REFENTRYINFO },
+	{ "refentrytitle",	NODE_REFENTRYTITLE },
+	{ "refmeta",		NODE_REFMETA },
+	{ "refmetainfo",	NODE_REFMETAINFO },
+	{ "refmiscinfo",	NODE_REFMISCINFO },
+	{ "refname",		NODE_REFNAME },
+	{ "refnamediv",		NODE_REFNAMEDIV },
+	{ "refpurpose",		NODE_REFPURPOSE },
+	{ "refsect1",		NODE_SECTION },
+	{ "refsect2",		NODE_SECTION },
+	{ "refsect3",		NODE_SECTION },
+	{ "refsection",		NODE_SECTION },
+	{ "refsynopsisdiv",	NODE_REFSYNOPSISDIV },
+	{ "releaseinfo",	NODE_RELEASEINFO },
+	{ "replaceable",	NODE_REPLACEABLE },
+	{ "row",		NODE_ROW },
+	{ "sbr",		NODE_SBR },
+	{ "screen",		NODE_SCREEN },
+	{ "secondary",		NODE_SECONDARY },
+	{ "sect1",		NODE_SECTION },
+	{ "sect2",		NODE_SECTION },
+	{ "section",		NODE_SECTION },
+	{ "sgmltag",		NODE_SGMLTAG },
+	{ "simplelist",		NODE_SIMPLELIST },
+	{ "spanspec",		NODE_SPANSPEC },
+	{ "structname",		NODE_STRUCTNAME },
+	{ "subtitle",		NODE_SUBTITLE },
+	{ "surname",		NODE_SURNAME },
+	{ "synopsis",		NODE_SYNOPSIS },
+	{ "table",		NODE_TABLE },
+	{ "tbody",		NODE_TBODY },
+	{ "term",		NODE_TERM },
+	{ "tfoot",		NODE_TFOOT },
+	{ "tgroup",		NODE_TGROUP },
+	{ "thead",		NODE_THEAD },
+	{ "tip",		NODE_TIP },
+	{ "title",		NODE_TITLE },
+	{ "trademark",		NODE_TRADEMARK },
+	{ "type",		NODE_TYPE },
+	{ "ulink",		NODE_ULINK },
+	{ "userinput",		NODE_USERINPUT },
+	{ "variablelist",	NODE_VARIABLELIST },
+	{ "varlistentry",	NODE_VARLISTENTRY },
+	{ "varname",		NODE_VARNAME },
+	{ "warning",		NODE_WARNING },
+	{ "wordasword",		NODE_WORDASWORD },
+	{ "year",		NODE_YEAR },
+	{ NULL,			NODE__MAX }
 };
 
 static	int warn = 0;
@@ -211,10 +244,7 @@ xml_char(void *arg, const XML_Char *p, i
 	if (ps->stop || NODE_ROOT == ps->node)
 		return;
 
-	/* Not supposed to be collecting text. */
 	assert(NULL != ps->cur);
-	if (NODE_IGNTEXT & nodes[ps->node].flags)
-		return;
 
 	/*
 	 * Are we in the midst of processing text?
@@ -287,7 +317,7 @@ static void
 xml_elem_start(void *arg, const XML_Char *name, const XML_Char **atts)
 {
 	struct parse	 *ps = arg;
-	enum nodeid	  node;
+	const struct node *node;
 	enum attrkey	  key;
 	enum attrval	  val;
 	struct pnode	 *dat;
@@ -307,15 +337,13 @@ xml_elem_start(void *arg, const XML_Char
 		ps->node = ps->cur->node;
 	}
 
-	for (node = 0; node < NODE__MAX; node++)
-		if (NULL == nodes[node].name)
-			continue;
-		else if (0 == strcmp(nodes[node].name, name))
+	for (node = nodes; NULL != node->name; node++)
+		if (0 == strcmp(node->name, name))
 			break;
 
-	if (NODE__MAX == node && NODE_ROOT == ps->node) {
-		return;
-	} else if (NODE__MAX == node) {
+	if (NULL == node->name) {
+		if (NODE_ROOT == ps->node)
+			return;
 		fprintf(stderr, "%s:%zu:%zu: unknown node \"%s\"\n",
 			ps->fname, XML_GetCurrentLineNumber(ps->xml),
 			XML_GetCurrentColumnNumber(ps->xml), name);
@@ -327,22 +355,9 @@ xml_elem_start(void *arg, const XML_Char
 			XML_GetCurrentColumnNumber(ps->xml));
 		ps->stop = 1;
 		return;
-	} else if (NODE_ROOT == ps->node && NODE_REFENTRY != node) {
-		return;
-	} else if ( ! isparent(node, ps->node)) {
-		fprintf(stderr, "%s:%zu:%zu: bad parent \"%s\" "
-			"of node \"%s\"\n",
-			ps->fname, XML_GetCurrentLineNumber(ps->xml),
-			XML_GetCurrentColumnNumber(ps->xml),
-			NULL == nodes[ps->node].name ?
-			"(none)" : nodes[ps->node].name,
-			NULL == nodes[node].name ?
-			"(none)" : nodes[node].name);
-		ps->stop = 1;
-		return;
 	}
 
-	if (NODE_INLINEEQUATION == node)
+	if (NODE_INLINEEQUATION == node->node)
 		ps->flags |= PARSE_EQN;
 
 	if (NULL == (dat = calloc(1, sizeof(struct pnode)))) {
@@ -350,7 +365,7 @@ xml_elem_start(void *arg, const XML_Char
 		exit(EXIT_FAILURE);
 	}
 
-	dat->node = ps->node = node;
+	dat->node = ps->node = node->node;
 	dat->parent = ps->cur;
 	TAILQ_INIT(&dat->childq);
 	TAILQ_INIT(&dat->attrq);
@@ -378,7 +393,7 @@ xml_elem_start(void *arg, const XML_Char
 					XML_GetCurrentColumnNumber(ps->xml),
 					*att);
 			continue;
-		} else if ( ! isattrkey(node, key)) {
+		} else if ( ! isattrkey(node->node, key)) {
 			if (warn)
 				fprintf(stderr, "%s:%zu:%zu: warning: "
 					"bad attribute \"%s\"\n",
@@ -683,6 +698,23 @@ pnode_printmclosepunct(struct parse *p, 
 	p->newln = 1;
 }
 
+static void
+pnode_printpara(struct parse *p, struct pnode *pn)
+{
+	struct pnode	*pp;
+
+	assert(p->newln);
+	if (NULL == pn->parent || NODE_LISTITEM == pn->parent->node)
+		return;
+
+	pp = TAILQ_PREV(pn, pnodeq, child);
+	if (NULL == pp)
+		pp = pn->parent;
+	if ((NODE_SECTION != pp->node && NODE_PREFACE != pp->node) ||
+	    2 < p->level)
+		puts(".Pp");
+}
+
 /*
  * If the SYNOPSIS macro has a superfluous title, kill it.
  */
@@ -705,53 +737,74 @@ static void
 pnode_printrefsect(struct parse *p, struct pnode *pn)
 {
 	struct pnode	*pp;
+	const char	*title;
+	int		 flags, level;
+
+	if (NULL == pn->parent)
+		return;
+
+	level = ++p->level;
+	flags = 1 == level ? MACROLINE_UPPER : 0;
+	if (3 > level) {
+		switch (pn->node) {
+		case (NODE_CAUTION):
+		case (NODE_NOTE):
+		case (NODE_TIP):
+		case (NODE_WARNING):
+			level = 3;
+			break;
+		default:
+			break;
+		}
+	}
 
 	TAILQ_FOREACH(pp, &pn->childq, child)
 		if (NODE_TITLE == pp->node)
 			break;
 
-	switch (pn->node) {
-	case (NODE_REFSECT1):
+	if (NULL == pp) {
+		switch (pn->node) {
+		case (NODE_PREFACE):
+			title = "Preface";
+			break;
+		case (NODE_CAUTION):
+			title = "Caution";
+			break;
+		case (NODE_NOTE):
+			title = "Note";
+			break;
+		case (NODE_TIP):
+			title = "Tip";
+			break;
+		case (NODE_WARNING):
+			title = "Warning";
+			break;
+		default:
+			title = "Unknown";
+			break;
+		}
+	}
+
+	switch (level) {
+	case (1):
 		fputs(".Sh", stdout);
 		break;
-	case (NODE_REFSECT2):
+	case (2):
 		fputs(".Ss", stdout);
 		break;
-	case (NODE_REFSECT3):
-		puts(".Pp");
-		fputs(".Sy", stdout);
-		break;
-	case (NODE_NOTE):
-		/* FALLTHROUGH */
-	case (NODE_REFSECTION):
-		/* FALLTHROUGH */
-	case (NODE_TIP):
-		/* FALLTHROUGH */
-	case (NODE_CAUTION):
-		/* FALLTHROUGH */
-	case (NODE_WARNING):
-		puts(".Pp");
-		if (NULL == pp)
-			return;
-		fputs(".Em", stdout);
-		break;
 	default:
+		pnode_printpara(p, pn);
+		fputs(".Sy", stdout);
 		break;
 	}
 
-	p->newln = 0;
-
 	if (NULL != pp) {
-		pnode_printmacrolinetext(p, pp,
-			NODE_REFSECT1 == pn->node ?
-			MACROLINE_UPPER : 0);
+		p->newln = 0;
+		pnode_printmacrolinetext(p, pp, flags);
 		pnode_printmclose(p, 1);
 		pnode_unlink(pp);
-	} else {
-		puts(NODE_REFSECT1 == pn->node ?
-			"UNKNOWN" : "unknown");
-		p->newln = 1;
-	}
+	} else
+		printf(" %s\n", title);
 }
 
 /*
@@ -794,7 +847,6 @@ pnode_printrefmeta(struct parse *p, stru
 		else if (NODE_REFENTRYTITLE == pp->node)
 			title = pp;
 
-	puts(".Dd $Mdocdate" "$");
 	fputs(".Dt", stdout);
 	p->newln = 0;
 
@@ -808,8 +860,6 @@ pnode_printrefmeta(struct parse *p, stru
 		p->newln = 1;
 	} else
 		pnode_printmacroline(p, manvol);
-
-	puts(".Os");
 }
 
 static void
@@ -1057,19 +1107,27 @@ static void
 pnode_printprologue(struct parse *p, struct pnode *pn)
 {
 	struct pnode	*pp;
+	struct pattr	*ap;
+	const char	*name;
 
 	pp = NULL == p->root ? NULL :
 		pnode_findfirst(p->root, NODE_REFMETA);
 
+	puts(".Dd $Mdocdate" "$");
 	if (NULL != pp) {
 		pnode_printrefmeta(p, pp);
 		pnode_unlink(pp);
 	} else {
-		puts(".\\\" Supplying bogus prologue...");
-		puts(".Dd $Mdocdate" "$");
-		puts(".Dt UNKNOWN 1");
-		puts(".Os");
+		name = "UNKNOWN";
+		TAILQ_FOREACH(ap, &p->root->attrq, child) {
+			if (ATTRKEY_ID == ap->key) {
+				name = ap->rawval;
+				break;
+			}
+		}
+		printf(".Dt %s 1\n", name);
 	}
+	puts(".Os");
 
 	if (PARSE_EQN & p->flags) {
 		puts(".EQ");
@@ -1131,7 +1189,7 @@ pnode_printtable(struct parse *p, struct
 	assert(p->newln);
 	TAILQ_FOREACH(pp, &pn->childq, child)
 		if (NODE_TITLE == pp->node) {
-			puts(".Pp");
+			pnode_printpara(p, pp);
 			pnode_print(p, pp);
 			pnode_unlink(pp);
 		}
@@ -1155,7 +1213,7 @@ pnode_printlist(struct parse *p, struct 
 	assert(p->newln);
 	TAILQ_FOREACH(pp, &pn->childq, child)
 		if (NODE_TITLE == pp->node) {
-			puts(".Pp");
+			pnode_printpara(p, pp);
 			pnode_print(p, pp);
 			pnode_unlink(pp);
 		}
@@ -1164,7 +1222,7 @@ pnode_printlist(struct parse *p, struct 
 	if (NODE_ORDEREDLIST == pn->node)
 		puts(".Bl -enum");
 	else
-		puts(".Bl -item");
+		puts(".Bl -bullet");
 
 	TAILQ_FOREACH(pp, &pn->childq, child) {
 		assert(p->newln);
@@ -1184,7 +1242,7 @@ pnode_printvariablelist(struct parse *p,
 	assert(p->newln);
 	TAILQ_FOREACH(pp, &pn->childq, child)
 		if (NODE_TITLE == pp->node) {
-			puts(".Pp");
+			pnode_printpara(p, pp);
 			pnode_print(p, pp);
 			pnode_unlink(pp);
 		}
@@ -1222,6 +1280,7 @@ pnode_print(struct parse *p, struct pnod
 
 	sv = p->newln;
 
+	/* XXX fprintf(stderr, "NODE %s\n", nodes[pn->node].name); */
 	switch (pn->node) {
 	case (NODE_APPLICATION):
 		pnode_printmopen(p);
@@ -1234,6 +1293,18 @@ pnode_print(struct parse *p, struct pnod
 		pnode_printarg(p, pn);
 		pnode_unlinksub(pn);
 		break;
+	case (NODE_AUTHOR):
+		pnode_printmopen(p);
+		fputs("An", stdout);
+		break;
+	case (NODE_AUTHORGROUP):
+		assert(p->newln);
+		puts(".An -split");
+		break;
+	case (NODE_BOOKINFO):
+		assert(p->newln);
+		puts(".Sh NAME");
+		break;
 	case (NODE_CITEREFENTRY):
 		pnode_printmopen(p);
 		fputs("Xr", stdout);
@@ -1252,6 +1323,11 @@ pnode_print(struct parse *p, struct pnod
 		pnode_printmopen(p);
 		fputs("Dv", stdout);
 		break;
+	case (NODE_EDITOR):
+		puts("editor: ");
+		pnode_printmopen(p);
+		fputs("An", stdout);
+		break;
 	case (NODE_EMPHASIS):
 		pnode_printmopen(p);
 		fputs("Em", stdout);
@@ -1277,6 +1353,8 @@ pnode_print(struct parse *p, struct pnod
 		pnode_printmopen(p);
 		fputs("Fd", stdout);
 		break;
+	case (NODE_INDEXTERM):
+		return;
 	case (NODE_INFORMALEQUATION):
 		if ( ! p->newln)
 			putchar('\n');
@@ -1296,6 +1374,10 @@ pnode_print(struct parse *p, struct pnod
 		pnode_printgroup(p, pn);
 		pnode_unlinksub(pn);
 		break;
+	case (NODE_LEGALNOTICE):
+		assert(p->newln);
+		puts(".Sh LEGAL NOTICE");
+		break;
 	case (NODE_LITERAL):
 		pnode_printmopen(p);
 		fputs("Li", stdout);
@@ -1328,11 +1410,7 @@ pnode_print(struct parse *p, struct pnod
 		pnode_unlinksub(pn);
 		break;
 	case (NODE_PARA):
-		assert(p->newln);
-		if (NULL != pn->parent &&
-			NODE_LISTITEM == pn->parent->node)
-			break;
-		puts(".Pp");
+		pnode_printpara(p, pn);
 		break;
 	case (NODE_PARAMETER):
 		/* Suppress non-text children... */
@@ -1346,6 +1424,8 @@ pnode_print(struct parse *p, struct pnod
 		pnode_printmopen(p);
 		fputs("Qo", stdout);
 		break;
+	case (NODE_LITERALLAYOUT):
+		/* FALLTHROUGH */
 	case (NODE_PROGRAMLISTING):
 		/* FALLTHROUGH */
 	case (NODE_SCREEN):
@@ -1381,20 +1461,11 @@ pnode_print(struct parse *p, struct pnod
 		pnode_printrefsynopsisdiv(p, pn);
 		puts(".Sh SYNOPSIS");
 		break;
-	case (NODE_REFSECT1):
-		/* FALLTHROUGH */
-	case (NODE_REFSECT2):
-		/* FALLTHROUGH */
-	case (NODE_REFSECT3):
-		/* FALLTHROUGH */
-	case (NODE_REFSECTION):
-		/* FALLTHROUGH */
+	case (NODE_PREFACE):
+	case (NODE_SECTION):
 	case (NODE_NOTE):
-		/* FALLTHROUGH */
 	case (NODE_TIP):
-		/* FALLTHROUGH */
 	case (NODE_CAUTION):
-		/* FALLTHROUGH */
 	case (NODE_WARNING):
 		assert(p->newln);
 		pnode_printrefsect(p, pn);
@@ -1469,6 +1540,12 @@ pnode_print(struct parse *p, struct pnod
 		}
 		p->newln = 0;
 		break;
+	case (NODE_TITLE):
+		if (pn->parent->node == NODE_BOOKINFO) {
+			pnode_printmopen(p);
+			fputs("Nd", stdout);
+		}
+		break;
 	case (NODE_TYPE):
 		pnode_printmopen(p);
 		fputs("Vt", stdout);
@@ -1518,10 +1595,12 @@ pnode_print(struct parse *p, struct pnod
 		break;
 	case (NODE_APPLICATION):
 	case (NODE_ARG):
+	case (NODE_AUTHOR):
 	case (NODE_CITEREFENTRY):
 	case (NODE_CODE):
 	case (NODE_COMMAND):
 	case (NODE_CONSTANT):
+	case (NODE_EDITOR):
 	case (NODE_EMPHASIS):
 	case (NODE_ENVAR):
 	case (NODE_FILENAME):
@@ -1560,12 +1639,28 @@ pnode_print(struct parse *p, struct pnod
 			fputs(" ,", stdout);
 		pnode_printmclose(p, sv);
 		break;
+	case (NODE_PREFACE):
+	case (NODE_SECTION):
+	case (NODE_NOTE):
+	case (NODE_TIP):
+	case (NODE_CAUTION):
+	case (NODE_WARNING):
+		p->level--;
+		break;
+	case (NODE_LITERALLAYOUT):
+		/* FALLTHROUGH */
 	case (NODE_PROGRAMLISTING):
 		/* FALLTHROUGH */
 	case (NODE_SCREEN):
 		assert(p->newln);
 		puts(".Ed");
 		p->newln = 1;
+		break;
+	case (NODE_TITLE):
+		if (pn->parent->node == NODE_BOOKINFO) {
+			pnode_printmclose(p, 1);
+			puts(".Sh AUTHORS");
+		}
 		break;
 	default:
 		break;
Index: extern.h
===================================================================
RCS file: /home/cvs/mdocml/docbook2mdoc/extern.h,v
retrieving revision 1.25
diff -u -p -r1.25 extern.h
--- extern.h	19 Mar 2015 10:04:32 -0000	1.25
+++ extern.h	9 Mar 2019 13:53:43 -0000
@@ -8,11 +8,18 @@ enum	nodeid {
 	NODE_ROOT = 0, /* Must comes first. */
 	/* Alpha-ordered hereafter. */
 	NODE_ACRONYM,
+	NODE_AFFILIATION,
 	NODE_ANCHOR,
 	NODE_APPLICATION,
 	NODE_ARG,
+	NODE_AUTHOR,
+	NODE_AUTHORGROUP,
+	NODE_BLOCKQUOTE,
+	NODE_BOOK,
+	NODE_BOOKINFO,
 	NODE_CAUTION,
 	NODE_CITEREFENTRY,
+	NODE_CITETITLE,
 	NODE_CMDSYNOPSIS,
 	NODE_CODE,
 	NODE_COLSPEC,
@@ -20,27 +27,38 @@ enum	nodeid {
 	NODE_CONSTANT,
 	NODE_COPYRIGHT,
 	NODE_DATE,
+	NODE_EDITOR,
 	NODE_EMPHASIS,
 	NODE_ENTRY,
 	NODE_ENVAR,
 	NODE_FIELDSYNOPSIS,
 	NODE_FILENAME,
+	NODE_FIRSTNAME,
+	NODE_FIRSTTERM,
+	NODE_FOOTNOTE,
 	NODE_FUNCDEF,
 	NODE_FUNCPROTOTYPE,
 	NODE_FUNCSYNOPSIS,
 	NODE_FUNCSYNOPSISINFO,
 	NODE_FUNCTION,
+	NODE_GLOSSTERM,
 	NODE_GROUP,
 	NODE_HOLDER,
+	NODE_INDEX,
+	NODE_INDEXTERM,
 	NODE_INFO,
 	NODE_INFORMALEQUATION,
 	NODE_INFORMALTABLE,
 	NODE_INLINEEQUATION,
 	NODE_ITEMIZEDLIST,
+	NODE_KEYSYM,
+	NODE_LEGALNOTICE,
 	NODE_LINK,
 	NODE_LISTITEM,
 	NODE_LITERAL,
+	NODE_LITERALLAYOUT,
 	NODE_MANVOLNUM,
+	NODE_MEMBER,
 	NODE_MML_MATH,
 	NODE_MML_MFENCED,
 	NODE_MML_MFRAC,
@@ -54,9 +72,14 @@ enum	nodeid {
 	NODE_NOTE,
 	NODE_OPTION,
 	NODE_ORDEREDLIST,
+	NODE_ORGNAME,
+	NODE_OTHERNAME,
 	NODE_PARA,
 	NODE_PARAMDEF,
 	NODE_PARAMETER,
+	NODE_PHRASE,
+	NODE_PREFACE,
+	NODE_PRIMARY,
 	NODE_PROGRAMLISTING,
 	NODE_PROMPT,
 	NODE_QUOTE,
@@ -71,17 +94,20 @@ enum	nodeid {
 	NODE_REFNAME,
 	NODE_REFNAMEDIV,
 	NODE_REFPURPOSE,
-	NODE_REFSECT1,
-	NODE_REFSECT2,
-	NODE_REFSECT3,
-	NODE_REFSECTION,
 	NODE_REFSYNOPSISDIV,
+	NODE_RELEASEINFO,
 	NODE_REPLACEABLE,
 	NODE_ROW,
 	NODE_SBR,
 	NODE_SCREEN,
+	NODE_SECONDARY,
+	NODE_SECTION,
 	NODE_SGMLTAG,
+	NODE_SIMPLELIST,
+	NODE_SPANSPEC,
 	NODE_STRUCTNAME,
+	NODE_SUBTITLE,
+	NODE_SURNAME,
 	NODE_SYNOPSIS,
 	NODE_TABLE,
 	NODE_TBODY,
@@ -136,7 +162,6 @@ __BEGIN_DECLS
 
 int isattrkey(enum nodeid node, enum attrkey key);
 int isattrval(enum attrkey key, enum attrval val);
-int isparent(enum nodeid node, enum nodeid parent);
 
 __END_DECLS
 
Index: rules.c
===================================================================
RCS file: /home/cvs/mdocml/docbook2mdoc/rules.c,v
retrieving revision 1.25
diff -u -p -r1.25 rules.c
--- rules.c	19 Mar 2015 10:04:32 -0000	1.25
+++ rules.c	9 Mar 2019 13:53:43 -0000
@@ -56,1334 +56,3 @@ isattrval(enum attrkey key, enum attrval
 	abort();
 	return(0);
 }
-
-/*
- * Look up whether "parent" is a valid parent for "node".
- * This is sucked directly from the DocBook specification: look at the
- * "children" and "parent" sections of each node.
- */
-int
-isparent(enum nodeid node, enum nodeid parent)
-{
-
-	switch (node) {
-	case (NODE_ROOT):
-		return(0);
-	case (NODE_ACRONYM):
-		switch (parent) {
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_ANCHOR):
-		/* We'll ignore this. */
-		return(1);
-	case (NODE_APPLICATION):
-		switch (parent) {
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFCLASS):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_ARG):
-		switch (parent) {
-		case (NODE_ARG):
-		case (NODE_CMDSYNOPSIS):
-		case (NODE_GROUP):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_CAUTION):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_LISTITEM):
-		case (NODE_NOTE):
-		case (NODE_ORDEREDLIST):
-		case (NODE_PARA):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_TIP):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_CITEREFENTRY):
-		switch (parent) {
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_CMDSYNOPSIS):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_LISTITEM):
-		case (NODE_ORDEREDLIST):
-		case (NODE_NOTE):
-		case (NODE_PARA):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_TIP):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_CODE):
-		switch (parent) {
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-		case (NODE_USERINPUT):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_COLSPEC):
-		switch (parent) {
-		case (NODE_TFOOT):
-		case (NODE_THEAD):
-		case (NODE_TGROUP):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_COMMAND):
-		switch (parent) {
-		case (NODE_CMDSYNOPSIS):
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-		case (NODE_USERINPUT):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_CONSTANT):
-		switch (parent) {
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_ULINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_USERINPUT):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_COPYRIGHT):
-		switch (parent) {
-		case (NODE_INFO):
-		case (NODE_REFENTRYINFO):
-		case (NODE_REFMETAINFO):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_DATE):
-		switch (parent) {
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_INFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYINFO):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_EMPHASIS):
-		switch (parent) {
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_ENTRY):
-		return(NODE_ROW == parent);
-	case (NODE_ENVAR):
-		switch (parent) {
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-		case (NODE_USERINPUT):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_FIELDSYNOPSIS):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_LISTITEM):
-		case (NODE_NOTE):
-		case (NODE_ORDEREDLIST):
-		case (NODE_PARA):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_TIP):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_FILENAME):
-		switch (parent) {
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-		case (NODE_USERINPUT):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_FUNCDEF):
-		return(NODE_FUNCPROTOTYPE == parent);
-	case (NODE_FUNCPROTOTYPE):
-		return(NODE_FUNCSYNOPSIS == parent);
-	case (NODE_FUNCSYNOPSIS):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_LISTITEM):
-		case (NODE_ORDEREDLIST):
-		case (NODE_NOTE):
-		case (NODE_PARA):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_TIP):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_FUNCSYNOPSISINFO):
-		return(NODE_FUNCSYNOPSIS == parent);
-	case (NODE_FUNCTION):
-		switch (parent) {
-		case (NODE_CODE):
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCDEF):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_GROUP):
-		switch (parent) {
-		case (NODE_ARG):
-		case (NODE_CMDSYNOPSIS):
-		case (NODE_GROUP):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_HOLDER):
-		switch (parent) {
-		case (NODE_COPYRIGHT):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_INFO):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_CMDSYNOPSIS):
-		case (NODE_FUNCSYNOPSIS):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_INFORMALTABLE):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_NOTE):
-		case (NODE_ORDEREDLIST):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_REFENTRY):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TABLE):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_INFORMALEQUATION):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_LISTITEM):
-		case (NODE_NOTE):
-		case (NODE_ORDEREDLIST):
-		case (NODE_PARA):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_INLINEEQUATION):
-		switch (parent) {
-		case (NODE_APPLICATION):
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_ITEMIZEDLIST):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_LISTITEM):
-		case (NODE_NOTE):
-		case (NODE_ORDEREDLIST):
-		case (NODE_PARA):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_TIP):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_LINK):
-	case (NODE_ULINK): /* Synonyms. */
-		switch (parent) {
-		case (NODE_ACRONYM):
-		case (NODE_APPLICATION):
-		case (NODE_ARG):
-		case (NODE_CODE):
-		case (NODE_COMMAND):
-		case (NODE_CONSTANT):
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_ENVAR):
-		case (NODE_FILENAME):
-		case (NODE_FUNCDEF):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_FUNCTION):
-		case (NODE_HOLDER):
-		case (NODE_LINK):
-		case (NODE_LITERAL):
-		case (NODE_MANVOLNUM):
-		case (NODE_MODIFIER):
-		case (NODE_OPTION):
-		case (NODE_PARA):
-		case (NODE_PARAMDEF):
-		case (NODE_PARAMETER):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_PROMPT):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFMISCINFO):
-		case (NODE_REFNAME):
-		case (NODE_REPLACEABLE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TRADEMARK):
-		case (NODE_TYPE):
-		case (NODE_ULINK):
-		case (NODE_USERINPUT):
-		case (NODE_VARNAME):
-		case (NODE_WORDASWORD):
-		case (NODE_YEAR):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_LISTITEM):
-		switch (parent) {
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_ORDEREDLIST):
-		case (NODE_VARLISTENTRY):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_LITERAL):
-		switch (parent) {
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-		case (NODE_USERINPUT):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_MANVOLNUM):
-		switch (parent) {
-		case (NODE_CITEREFENTRY):
-		case (NODE_REFMETA):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_MML_MATH):
-		switch (parent) {
-		case (NODE_INFORMALEQUATION):
-		case (NODE_INLINEEQUATION):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_MML_MFENCED):
-	case (NODE_MML_MFRAC):
-	case (NODE_MML_MI):
-	case (NODE_MML_MN):
-	case (NODE_MML_MO):
-	case (NODE_MML_MROW):
-	case (NODE_MML_MSUB):
-	case (NODE_MML_MSUP):
-		switch (parent) {
-		case (NODE_MML_MATH):
-		case (NODE_MML_MFENCED):
-		case (NODE_MML_MFRAC):
-		case (NODE_MML_MI):
-		case (NODE_MML_MN):
-		case (NODE_MML_MO):
-		case (NODE_MML_MROW):
-		case (NODE_MML_MSUB):
-		case (NODE_MML_MSUP):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_MODIFIER):
-		switch (parent) {
-		case (NODE_CODE):
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FIELDSYNOPSIS):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_ULINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_NOTE):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_LISTITEM):
-		case (NODE_NOTE):
-		case (NODE_ORDEREDLIST):
-		case (NODE_PARA):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_TIP):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_OPTION):
-		switch (parent) {
-		case (NODE_ARG):
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_GROUP):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-		case (NODE_USERINPUT):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_ORDEREDLIST):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_LISTITEM):
-		case (NODE_ORDEREDLIST):
-		case (NODE_NOTE):
-		case (NODE_PARA):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_TIP):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_PARA):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_LISTITEM):
-		case (NODE_NOTE):
-		case (NODE_ORDEREDLIST):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_TIP):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_PARAMDEF):
-		return(NODE_FUNCPROTOTYPE == parent);
-	case (NODE_PARAMETER):
-		switch (parent) {
-		case (NODE_CODE):
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PARAMDEF):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-		case (NODE_USERINPUT):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_PROGRAMLISTING):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_LISTITEM):
-		case (NODE_ORDEREDLIST):
-		case (NODE_NOTE):
-		case (NODE_PARA):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_TIP):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_PROMPT):
-		switch (parent) {
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-		case (NODE_USERINPUT):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_QUOTE):
-		switch (parent) {
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_REFCLASS):
-		return(parent == NODE_REFNAMEDIV);
-	case (NODE_REFDESCRIPTOR):
-		return(parent == NODE_REFNAMEDIV);
-	case (NODE_REFENTRY):
-		return(parent == NODE_ROOT);
-	case (NODE_REFENTRYINFO):
-		return(parent == NODE_REFENTRY);
-	case (NODE_REFENTRYTITLE):
-		switch (parent) {
-		case (NODE_CITEREFENTRY):
-		case (NODE_REFMETA):
-			return(1);
-		default:
-			break;
-		}
-	case (NODE_REFMETA):
-		return(parent == NODE_REFENTRY);
-	case (NODE_REFMETAINFO):
-		return(parent == NODE_REFMETA);
-	case (NODE_REFMISCINFO):
-		return(parent == NODE_REFMETA);
-	case (NODE_REFNAME):
-		return(parent == NODE_REFNAMEDIV);
-	case (NODE_REFNAMEDIV):
-		return(parent == NODE_REFENTRY);
-	case (NODE_REFPURPOSE):
-		return(parent == NODE_REFNAMEDIV);
-	case (NODE_REFSECT1):
-		return(parent == NODE_REFENTRY);
-	case (NODE_REFSECT2):
-		switch (parent) {
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_REFSECT1):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_REFSECT3):
-		return(parent == NODE_REFSECT2);
-	case (NODE_REFSECTION):
-		switch (parent) {
-		case (NODE_REFENTRY):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_REFSYNOPSISDIV):
-		return(parent == NODE_REFENTRY);
-	case (NODE_REPLACEABLE):
-		switch (parent) {
-		case (NODE_ACRONYM):
-		case (NODE_APPLICATION):
-		case (NODE_ARG):
-		case (NODE_CODE):
-		case (NODE_COMMAND):
-		case (NODE_CONSTANT):
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_ENVAR):
-		case (NODE_FILENAME):
-		case (NODE_FUNCDEF):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_FUNCTION):
-		case (NODE_GROUP):
-		case (NODE_HOLDER):
-		case (NODE_LINK):
-		case (NODE_LITERAL):
-		case (NODE_MANVOLNUM):
-		case (NODE_MODIFIER):
-		case (NODE_OPTION):
-		case (NODE_PARA):
-		case (NODE_PARAMDEF):
-		case (NODE_PARAMETER):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_PROMPT):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFMISCINFO):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_REPLACEABLE):
-		case (NODE_SCREEN):
-		case (NODE_SGMLTAG):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_TRADEMARK):
-		case (NODE_TYPE):
-		case (NODE_ULINK):
-		case (NODE_USERINPUT):
-		case (NODE_VARNAME):
-		case (NODE_WORDASWORD):
-		case (NODE_YEAR):
-		default:
-			return(1);
-		}
-		return(0);
-	case (NODE_ROW):
-		switch (parent) {
-		case (NODE_TBODY):
-		case (NODE_TFOOT):
-		case (NODE_THEAD):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_SBR):
-		switch (parent) {
-		case (NODE_ARG):
-		case (NODE_CMDSYNOPSIS):
-		case (NODE_GROUP):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_SCREEN):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_LISTITEM):
-		case (NODE_ORDEREDLIST):
-		case (NODE_NOTE):
-		case (NODE_PARA):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_TIP):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_SGMLTAG):
-		switch (parent) {
-		case (NODE_APPLICATION):
-		case (NODE_CODE):
-		case (NODE_COMMAND):
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FILENAME):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_FUNCTION):
-		case (NODE_LINK):
-		case (NODE_LITERAL):
-		case (NODE_OPTION):
-		case (NODE_PARA):
-		case (NODE_PARAMETER):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_USERINPUT):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_STRUCTNAME):
-		switch (parent) {
-		case (NODE_CODE):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_FUNCTION):
-		case (NODE_OPTION):
-		case (NODE_PARA):
-		case (NODE_PARAMETER):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SYNOPSIS):
-		case (NODE_TITLE):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_SYNOPSIS):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_LISTITEM):
-		case (NODE_ORDEREDLIST):
-		case (NODE_NOTE):
-		case (NODE_PARA):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_TIP):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_INFORMALTABLE):
-		/* FALLTHROUGH */
-	case (NODE_TABLE):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_LISTITEM):
-		case (NODE_ORDEREDLIST):
-		case (NODE_NOTE):
-		case (NODE_PARA):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_TIP):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_TBODY):
-		return(NODE_TGROUP == parent);
-	case (NODE_TFOOT):
-		return(NODE_TGROUP == parent);
-	case (NODE_TGROUP):
-		switch (parent) {
-		case (NODE_INFORMALTABLE):
-		case (NODE_TABLE):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_THEAD):
-		return(NODE_TGROUP == parent);
-	case (NODE_TITLE):
-		switch (parent) {
-		case (NODE_INFO):
-		case (NODE_INFORMALTABLE):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_ORDEREDLIST):
-		case (NODE_REFENTRYINFO):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_TABLE):
-		case (NODE_VARIABLELIST):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_TERM):
-		return(NODE_VARLISTENTRY == parent);
-	case (NODE_TEXT):
-		return(1);
-	case (NODE_TIP):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_LISTITEM):
-		case (NODE_NOTE):
-		case (NODE_ORDEREDLIST):
-		case (NODE_PARA):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_TIP):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_TRADEMARK):
-		switch (parent) {
-		case (NODE_ACRONYM):
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_ULINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_TYPE):
-		switch (parent) {
-		case (NODE_CODE):
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FIELDSYNOPSIS):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_ULINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_USERINPUT):
-		switch (parent) {
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-		case (NODE_USERINPUT):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_VARIABLELIST):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_ORDEREDLIST):
-		case (NODE_NOTE):
-		case (NODE_PARA):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_TIP):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_VARNAME):
-		switch (parent) {
-		case (NODE_CODE):
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FIELDSYNOPSIS):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_VARLISTENTRY):
-		return (NODE_VARIABLELIST == parent);
-	case (NODE_WARNING):
-		switch (parent) {
-		case (NODE_CAUTION):
-		case (NODE_ENTRY):
-		case (NODE_ITEMIZEDLIST):
-		case (NODE_LISTITEM):
-		case (NODE_NOTE):
-		case (NODE_ORDEREDLIST):
-		case (NODE_PARA):
-		case (NODE_REFSECT1):
-		case (NODE_REFSECT2):
-		case (NODE_REFSECT3):
-		case (NODE_REFSECTION):
-		case (NODE_REFSYNOPSISDIV):
-		case (NODE_TIP):
-		case (NODE_VARIABLELIST):
-		case (NODE_WARNING):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_WORDASWORD):
-		switch (parent) {
-		case (NODE_EMPHASIS):
-		case (NODE_ENTRY):
-		case (NODE_FUNCSYNOPSISINFO):
-		case (NODE_LINK):
-		case (NODE_PARA):
-		case (NODE_PROGRAMLISTING):
-		case (NODE_QUOTE):
-		case (NODE_REFDESCRIPTOR):
-		case (NODE_REFENTRYTITLE):
-		case (NODE_REFNAME):
-		case (NODE_REFPURPOSE):
-		case (NODE_SCREEN):
-		case (NODE_SYNOPSIS):
-		case (NODE_TERM):
-		case (NODE_TITLE):
-		case (NODE_ULINK):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE_YEAR):
-		switch (parent) {
-		case (NODE_COPYRIGHT):
-			return(1);
-		default:
-			break;
-		}
-		return(0);
-	case (NODE__MAX):
-		break;
-	}
-
-	abort();
-	return(0);
-}
-


 ----- 8< ----- schnipp ----- >8 ----- 8< ----- schnapp ----- >8 -----

  *** Here is my longer rationale ***

Ingo Schwarze wrote on Sun, Feb 24, 2019 at 06:10:18PM +0100:

> one project i'm currently working on is using docbook2mdoc(1) to
> format the xorgproto manuals in /usr/xenocara/proto/xorgproto/specs/
> such that they can be installed into /usr/X11R6/man/.
> 
> I know that you originally only aimed for <refentry>, but i don't
> really see the point in that limitation.
> 
> Following the process described in the README, i already have a
> gigantic and unreadable 2000-line patch (not intended for commit
> in its current form), mostly adding cruft to rules.c, and i'm
> still not able to parse all the documents for xorgproto, let alone
> nicely represent them.
> 
> I absolutely see why a validating parser makes sense for a well
> designed language like mdoc(7), and even for a simplistic language
> like man(7), but after doing some real work on the docbook2mdoc
> parser, i fail to see the point in even attempting to validate
> DocBook input.
> 
> Obviously, DocBook is a language designed by a bunch of utter morons.
> Or maybe more to the point, there isn't the slightest trace of any
> kind of design visible anywhere, it is nothing but a gigantic
> accretion of arbitrary elements, piled on top of each other without
> the slightest sense of method or cohesion.  What is allowed where
> is totally arbitrary and makes no sense whatsoever.  Besides, the
> number of rules is so large that no human being has a chance to
> learn them: authors are obviously forced to constantly refer to the
> documentation such that they can obey the plethora of arbitrary
> restrictions.
> 
> Besides, we are absolutely not encouraging anybody to produce DocBook
> documents.  So why should we bother whether existing legacy documents
> are valid?
> 
> I suggest to completely ditch all the validation code from
> docbook2mdoc(1) and instead just happily accept *any* nesting
> whatsoever.  That would make the code much samller and simpler and
> allow a huge boost in development speed.  It would also allow to
> focus on good representation instead of having to foxus on parsing.
> 
> Of course, the formatter has to make sure that the nesting of the
> generated mdoc(7) elements is valid.  But that actually becomes
> *simpler* ditching the validation.  For example, if we effectively
> map the whole plethora of sectioning elements (book, chapter, part,
> refentry, refsect1, refsect2, refsect3, refsection, sect1, sect2,
> section, ...) to a single node type, then the formatter can easily
> map the outermost, whatever it may be in a given document, to .Sh,
> the next one inside to .Ss, and the next one inside to .Pp Sy ... Pp.
> 
> What do you think?
> 
> Should i propose a patch doing that, or maybe even just go ahead,
> i.e. develop it and commit it without bothering you more?


 ----- 8< ----- schnipp ----- >8 ----- 8< ----- schnapp ----- >8 -----

  *** Here comes Stephen's conflicting patch ***

Stephen Gregoratto wrote on Fri, Mar 22, 2019 at 09:33:57PM +1100:

> Add support for the <email> node. The official XSL stylesheets enclose 
> the address in angle brackets, and so shall we. While we're at it, add a 
> missing return statement for NODE_REFENTRYTITLE.
> 
> I intend to add more nodes in the future so I'm starting with a small 
> addition to get a feel of the code-base. Critique is fully welcome here.
> I hope to add <author> node soon, so we can generate a full `.An` block.
> For example:
> 
>   <author>
>     <personname>
>       <firstname>Joe</firstname>
>       <othername>Bloggo</othername>
>       <surname>Bloggs</surname>
>     </personname>
>     <email>joe@foo.net</email>
>   </author>
> 
> Would transform into:
> 
>   .An Joe So Bloggo Sq Bloggs Aq Mt joe@foo.net
> 
> The othername part may be overkill right now. Not sure if this would 
> require it's own function like pnode_printrefsect().
> 
> Index: docbook2mdoc.c
> ===================================================================
> RCS file: /cvs/docbook2mdoc/docbook2mdoc.c,v
> retrieving revision 1.47
> diff -u -p -r1.47 docbook2mdoc.c
> --- docbook2mdoc.c	8 Mar 2019 15:18:50 -0000	1.47
> +++ docbook2mdoc.c	22 Mar 2019 10:07:15 -0000
> @@ -105,6 +105,7 @@ static	const struct node nodes[NODE__MAX
>  	{ "constant", 0 },
>  	{ "copyright", NODE_IGNTEXT },
>  	{ "date", 0 },
> +	{ "email", 0 },
>  	{ "emphasis", 0 },
>  	{ "entry", 0 },
>  	{ "envar", 0 },
> @@ -1252,6 +1253,10 @@ pnode_print(struct parse *p, struct pnod
>  		pnode_printmopen(p);
>  		fputs("Dv", stdout);
>  		break;
> +	case (NODE_EMAIL):
> +		pnode_printmopen(p);
> +		fputs("Aq Mt", stdout);
> +		break;
>  	case (NODE_EMPHASIS):
>  		pnode_printmopen(p);
>  		fputs("Em", stdout);
> @@ -1522,6 +1527,7 @@ pnode_print(struct parse *p, struct pnod
>  	case (NODE_CODE):
>  	case (NODE_COMMAND):
>  	case (NODE_CONSTANT):
> +	case (NODE_EMAIL):
>  	case (NODE_EMPHASIS):
>  	case (NODE_ENVAR):
>  	case (NODE_FILENAME):
> Index: extern.h
> ===================================================================
> RCS file: /cvs/docbook2mdoc/extern.h,v
> retrieving revision 1.25
> diff -u -p -r1.25 extern.h
> --- extern.h	19 Mar 2015 10:04:32 -0000	1.25
> +++ extern.h	22 Mar 2019 10:07:15 -0000
> @@ -20,6 +20,7 @@ enum	nodeid {
>  	NODE_CONSTANT,
>  	NODE_COPYRIGHT,
>  	NODE_DATE,
> +	NODE_EMAIL,
>  	NODE_EMPHASIS,
>  	NODE_ENTRY,
>  	NODE_ENVAR,
> Index: rules.c
> ===================================================================
> RCS file: /cvs/docbook2mdoc/rules.c,v
> retrieving revision 1.25
> diff -u -p -r1.25 rules.c
> --- rules.c	19 Mar 2015 10:04:32 -0000	1.25
> +++ rules.c	22 Mar 2019 10:07:15 -0000
> @@ -71,6 +71,7 @@ isparent(enum nodeid node, enum nodeid p
>  		return(0);
>  	case (NODE_ACRONYM):
>  		switch (parent) {
> +		case (NODE_EMAIL):
>  		case (NODE_EMPHASIS):
>  		case (NODE_ENTRY):
>  		case (NODE_FUNCSYNOPSISINFO):
> @@ -289,6 +290,7 @@ isparent(enum nodeid node, enum nodeid p
>  		return(0);
>  	case (NODE_DATE):
>  		switch (parent) {
> +		case (NODE_EMAIL):
>  		case (NODE_EMPHASIS):
>  		case (NODE_ENTRY):
>  		case (NODE_FUNCSYNOPSISINFO):
> @@ -311,8 +313,30 @@ isparent(enum nodeid node, enum nodeid p
>  			break;
>  		}
>  		return(0);
> +	case (NODE_EMAIL):
> +		switch (parent) {
> +		case (NODE_ENTRY):
> +		case (NODE_FUNCSYNOPSISINFO):
> +		case (NODE_LINK):
> +		case (NODE_PARA):
> +		case (NODE_PROGRAMLISTING):
> +		case (NODE_REFDESCRIPTOR):
> +		case (NODE_REFENTRYTITLE):
> +		case (NODE_REFNAME):
> +		case (NODE_REFPURPOSE):
> +		case (NODE_SCREEN):
> +		case (NODE_SYNOPSIS):
> +		case (NODE_TERM):
> +		case (NODE_TITLE):
> +		case (NODE_USERINPUT):
> +			return(1);
> +		default:
> +			break;
> +		}
> +		return(0);
>  	case (NODE_EMPHASIS):
>  		switch (parent) {
> +		case (NODE_EMAIL):
>  		case (NODE_EMPHASIS):
>  		case (NODE_ENTRY):
>  		case (NODE_FUNCSYNOPSISINFO):
> @@ -577,6 +601,7 @@ isparent(enum nodeid node, enum nodeid p
>  		case (NODE_CODE):
>  		case (NODE_COMMAND):
>  		case (NODE_CONSTANT):
> +		case (NODE_EMAIL):
>  		case (NODE_EMPHASIS):
>  		case (NODE_ENTRY):
>  		case (NODE_ENVAR):
> @@ -883,6 +908,7 @@ isparent(enum nodeid node, enum nodeid p
>  		return(0);
>  	case (NODE_QUOTE):
>  		switch (parent) {
> +		case (NODE_EMAIL):
>  		case (NODE_EMPHASIS):
>  		case (NODE_ENTRY):
>  		case (NODE_FUNCSYNOPSISINFO):
> @@ -920,6 +946,7 @@ isparent(enum nodeid node, enum nodeid p
>  		default:
>  			break;
>  		}
> +		return(0);
>  	case (NODE_REFMETA):
>  		return(parent == NODE_REFENTRY);
>  	case (NODE_REFMETAINFO):
> @@ -966,6 +993,7 @@ isparent(enum nodeid node, enum nodeid p
>  		case (NODE_COMMAND):
>  		case (NODE_CONSTANT):
>  		case (NODE_EMPHASIS):
> +		case (NODE_EMAIL):
>  		case (NODE_ENTRY):
>  		case (NODE_ENVAR):
>  		case (NODE_FILENAME):
> @@ -1208,6 +1236,7 @@ isparent(enum nodeid node, enum nodeid p
>  	case (NODE_TRADEMARK):
>  		switch (parent) {
>  		case (NODE_ACRONYM):
> +		case (NODE_EMAIL):
>  		case (NODE_EMPHASIS):
>  		case (NODE_ENTRY):
>  		case (NODE_FUNCSYNOPSISINFO):
> @@ -1350,6 +1379,7 @@ isparent(enum nodeid node, enum nodeid p
>  		return(0);
>  	case (NODE_WORDASWORD):
>  		switch (parent) {
> +		case (NODE_EMAIL):
>  		case (NODE_EMPHASIS):
>  		case (NODE_ENTRY):
>  		case (NODE_FUNCSYNOPSISINFO):
--
 To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH docbook2mdoc] Add NODE_EMAIL
  2019-03-22 10:33 [PATCH docbook2mdoc] Add NODE_EMAIL Stephen Gregoratto
  2019-03-22 12:32 ` Ingo Schwarze
@ 2019-03-22 20:07 ` Ingo Schwarze
  2019-03-23  5:30   ` Stephen Gregoratto
  1 sibling, 1 reply; 7+ messages in thread
From: Ingo Schwarze @ 2019-03-22 20:07 UTC (permalink / raw)
  To: Stephen Gregoratto; +Cc: tech

Hi Stephen,

Stephen Gregoratto wrote on Fri, Mar 22, 2019 at 09:33:57PM +1100:

> Add support for the <email> node.

In the future, it might be useful to mention in which real-world
document(s) you found a given feature used.  There is no desire
to completely implement everything specified by DocBook.  Rather,
it is enough to implement parts actually used in practice.

> The official XSL stylesheets enclose the address in angle brackets,
> and so shall we.

In general, do not try to reproduce the *presentation* chosen by the
DocBook formatter by translating to mdoc(7) markup that results in
similar presentation.  Instead, find out what the DocBook markup is
intended to mean, then translate the *meaning* to mdoc(7) markup,
even if the resulting presentation differs that way.

In the case at hand, marking up an email address with ".Aq Mt" is
indeed conventional in mdoc(7).

> While we're at it, add a missing return statement for NODE_REFENTRYTITLE.

Rejoice: the file rules.c no longer exists.
Much less work to do in the future!

> I intend to add more nodes in the future

Thank you, help working on docbook2mdoc(1) is certainly welcome!

Just out of curiosity: What are you using docbook2mdoc(1) for?

[...]
> I hope to add <author> node soon, so we can generate a full `.An` block.

I had already done that some time ago, and i just committed lots
of patches i had in my tree.

> For example:
> 
>   <author>
>     <personname>
>       <firstname>Joe</firstname>
>       <othername>Bloggo</othername>
>       <surname>Bloggs</surname>
>     </personname>
>     <email>joe@foo.net</email>
>   </author>
> 
> Would transform into:
> 
>   .An Joe So Bloggo Sq Bloggs Aq Mt joe@foo.net

I assume you mean s/Sq/Sc/?

> The othername part may be overkill right now.

Possibly overkill, yes.  Or is it used a lot in practice?

> Not sure if this would require it's own function
> like pnode_printrefsect().

Off the top of my head, i can't say yet.
Macro nesting is certainly not among the easiest tasks in
docbook2mdoc(1), and the codebase is likely still fragile in that
respect.

I rebased your patch such that it applied to HEAD and committed it
in the following form.

Test results:
   $ cat tmp.txt
  <author>
    <personname>
      <firstname>Joe</firstname>
      <othername>Bloggo</othername>
      <surname>Bloggs</surname>
    </personname>
    <email>joe@foo.net</email>
  </author>
   $ ./docbook2mdoc tmp.txt | man -lc
UNKNOWN(1)                  General Commands Manual                 UNKNOWN(1)

Joe Bloggo Bloggs <joe@foo.net>

OpenBSD 6.4                     March 22, 2019                     OpenBSD 6.4

Thanks,
  Ingo


Log Message:
-----------
support <personname> and <email>;
based on a patch from Stephen Gregoratto <dev at sgregoratto dot me>

Modified Files:
--------------
    docbook2mdoc:
        docbook2mdoc.c
        extern.h

Revision Data
-------------
Index: extern.h
===================================================================
RCS file: /home/cvs/mdocml/docbook2mdoc/extern.h,v
retrieving revision 1.31
retrieving revision 1.32
diff -Lextern.h -Lextern.h -u -p -r1.31 -r1.32
--- extern.h
+++ extern.h
@@ -43,6 +43,7 @@ enum	nodeid {
 	NODE_COPYRIGHT,
 	NODE_DATE,
 	NODE_EDITOR,
+	NODE_EMAIL,
 	NODE_EMPHASIS,
 	NODE_ENTRY,
 	NODE_ENVAR,
@@ -92,6 +93,7 @@ enum	nodeid {
 	NODE_PARA,
 	NODE_PARAMDEF,
 	NODE_PARAMETER,
+	NODE_PERSONNAME,
 	NODE_PHRASE,
 	NODE_PREFACE,
 	NODE_PRIMARY,
Index: docbook2mdoc.c
===================================================================
RCS file: /home/cvs/mdocml/docbook2mdoc/docbook2mdoc.c,v
retrieving revision 1.64
retrieving revision 1.65
diff -Ldocbook2mdoc.c -Ldocbook2mdoc.c -u -p -r1.64 -r1.65
--- docbook2mdoc.c
+++ docbook2mdoc.c
@@ -117,6 +117,7 @@ static	const struct node nodes[] = {
 	{ "copyright",		NODE_COPYRIGHT },
 	{ "date",		NODE_DATE },
 	{ "editor",		NODE_EDITOR },
+	{ "email",		NODE_EMAIL },
 	{ "emphasis",		NODE_EMPHASIS },
 	{ "entry",		NODE_ENTRY },
 	{ "envar",		NODE_ENVAR },
@@ -167,6 +168,7 @@ static	const struct node nodes[] = {
 	{ "paramdef",		NODE_PARAMDEF },
 	{ "parameter",		NODE_PARAMETER },
 	{ "part",		NODE_SECTION },
+	{ "personname",		NODE_PERSONNAME },
 	{ "phrase",		NODE_PHRASE },
 	{ "preface",		NODE_PREFACE },
 	{ "primary",		NODE_PRIMARY },
@@ -1317,6 +1319,10 @@ pnode_print(struct parse *p, struct pnod
 		pnode_printmopen(p);
 		fputs("An", stdout);
 		break;
+	case NODE_EMAIL:
+		pnode_printmopen(p);
+		fputs("Aq Mt", stdout);
+		break;
 	case NODE_EMPHASIS:
 	case NODE_FIRSTTERM:
 		pnode_printmopen(p);
@@ -1600,6 +1606,7 @@ pnode_print(struct parse *p, struct pnod
 	case NODE_COMMAND:
 	case NODE_CONSTANT:
 	case NODE_EDITOR:
+	case NODE_EMAIL:
 	case NODE_EMPHASIS:
 	case NODE_ENVAR:
 	case NODE_FILENAME:
--
 To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH docbook2mdoc] Add NODE_EMAIL
  2019-03-22 20:07 ` Ingo Schwarze
@ 2019-03-23  5:30   ` Stephen Gregoratto
  2019-03-23  8:46     ` Ingo Schwarze
  0 siblings, 1 reply; 7+ messages in thread
From: Stephen Gregoratto @ 2019-03-23  5:30 UTC (permalink / raw)
  To: tech

On 2019-03-22 21:07, Ingo Schwarze wrote:
> In the future, it might be useful to mention in which real-world
> document(s) you found a given feature used.

The manpages for doclifter/manlifter[1] contain esr's email address 
enclosed in an <email> node. I've also come across the <author> block
in the GNOME project's GTK docs[2].

The big DocBook users are the FreeDesktop group and it's members: GNOME,
KDE, Systemd et al. If we work through the smaller cases (like GTK's),
we can eventually start thinking about how to transform longer and more
complicated ones. Case in point, this section I found in the GTK
docs[3].
 
> Thank you, help working on docbook2mdoc(1) is certainly welcome!
> Just out of curiosity: What are you using docbook2mdoc(1) for?

I've interacted with many manpage generators so far, so I thought I'd
make a good faith comparison between  the many I've seen/used in OSS.
I've decided I'd start with the generators I know the least, which are
refentry files. I was going to compare docbook2mdoc's output to the
official XSL stylesheets to see how they compare, But I can't compare
them if it exits on an unseen node ;).

Also, I do like using mdoc and mandoc and thought I could help out with
the DocBook converter. My personal goal is to convert most of the
systemd manpages, as they contain many tables/code listings that would
look good when going through mandoc's HTML output.

> I rebased your patch such that it applied to HEAD and committed it
> in the following form.
> 
> Test results:
>    $ cat tmp.txt
>   <author>
>     <personname>
>       <firstname>Joe</firstname>
>       <othername>Bloggo</othername>
>       <surname>Bloggs</surname>
>     </personname>
>     <email>joe@foo.net</email>
>   </author>
>    $ ./docbook2mdoc tmp.txt | man -lc
> UNKNOWN(1)                  General Commands Manual                 UNKNOWN(1)
> 
> Joe Bloggo Bloggs <joe@foo.net>
> 
> OpenBSD 6.4                     March 22, 2019                     OpenBSD 6.4

Cheers. Something I noticed is that many documents put the authors in
the <refmeta> section, which the XSL stylesheets move into AUTHORS. Not
sure how we would deal with this. Perhaps a string buffer or array of
struct author that could be printed out at the end/before
CAVEATS/BUGS et al.? For now I'll put my <author> node in its own
<refsect>.

[1] https://gitlab.com/esr/doclifter/raw/master/doclifter.xml
[2] https://gitlab.gnome.org/GNOME/gtk/raw/master/docs/reference/gtk/gtk4-launch.xml
[3] https://gitlab.gnome.org/GNOME/gtk/blob/master/docs/reference/gtk/css-overview.xml#L510
-- 
Stephen Gregoratto
PGP: 3FC6 3D0E 2801 C348 1C44 2D34 A80C 0F8E 8BAB EC8B
--
 To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH docbook2mdoc] Add NODE_EMAIL
  2019-03-23  5:30   ` Stephen Gregoratto
@ 2019-03-23  8:46     ` Ingo Schwarze
  2019-03-23 10:18       ` Stephen Gregoratto
  0 siblings, 1 reply; 7+ messages in thread
From: Ingo Schwarze @ 2019-03-23  8:46 UTC (permalink / raw)
  To: Stephen Gregoratto; +Cc: tech

Hi Stephen,

Stephen Gregoratto wrote on Sat, Mar 23, 2019 at 04:30:08PM +1100:
> On 2019-03-22 21:07, Ingo Schwarze wrote:

>> In the future, it might be useful to mention in which real-world
>> document(s) you found a given feature used.

> The manpages for doclifter/manlifter[1]

Oh.  That package is definitely important.

> contain esr's email address enclosed in an <email> node.
> I've also come across the <author> block in the GNOME project's
> GTK docs[2].
> 
> The big DocBook users are the FreeDesktop group and it's members: GNOME,
> KDE, Systemd et al. If we work through the smaller cases (like GTK's),
> we can eventually start thinking about how to transform longer and more
> complicated ones. Case in point, this section I found in the GTK
> docs[3].

All that makes a lot of sense to me.  Thanks for explaining.

>> Thank you, help working on docbook2mdoc(1) is certainly welcome!
>> Just out of curiosity: What are you using docbook2mdoc(1) for?

> I've interacted with many manpage generators so far, so I thought I'd
> make a good faith comparison between the many I've seen/used in OSS.
> I've decided I'd start with the generators I know the least, which are
> refentry files.

I can't say i have ever *used* the DocBook format, but the man(7)
output from DocBook files has struck me over and over again as the
by far lowest quality man(7) code i have ever seen from any manual
page generator.  DocBook is without any doubt the number one manual
page generation scheme causing the most trouble in real life, in
multiple respects.  By far.  So i am definitely not able to approach
DocBook in good faith; i strongly hate DocBook and i am heavily
biased against it based on previous experience.  But our different
perspective on it can likely be productive.  :)

> I was going to compare docbook2mdoc's output to the official XSL
> stylesheets to see how they compare, But I can't compare them if
> it exits on an unseen node ;).

Right.  Even though docbook2mdoc(1) is now five years old, it is
still clearly experimental software in an early stage of development.
The version number 0.0.9 makes sense in that respect.

> Also, I do like using mdoc and mandoc and thought I could help out
> with the DocBook converter.

Good, thanks.  I see at least three reasons why that might be useful:

 1. Some parts of X11 documentation currently exist in DocBook form.
    Short term, it is useful to convert them to mdoc(7) and install
    them as part of Xenocara in OpenBSD.

 2. Medium term, it might be an option to use docbook2mdoc(1) for
    building the documentation of (at least some) ports having
    DocBook documentation.  That is, run docbook2mdoc(1) at port
    build time and let the pkg install the resulting mdoc(7) files.
    Not sure yet how well that may work, but if it does, it would
    give users higher quality documentation, allowing semantic
    search in particular, better HTML output, and even better man(1)
    terminal output that better matches usual conventions.

 3. Long term, it might be possible to build a toolchain out of
    doclifter(1) and docbook2mdoc(1) to convert legacy man(7) manual
    pages to mdoc(7).  Not sure yet how well that may work.

> My personal goal is to convert most of the systemd manpages,
> as they contain many tables/code listings that would
> look good when going through mandoc's HTML output.

I see.  Even though systemd is not software that could reasonably
be ported to OpenBSD, i see your point.

> Cheers. Something I noticed is that many documents put the authors in
> the <refmeta> section, which the XSL stylesheets move into AUTHORS. Not
> sure how we would deal with this. Perhaps a string buffer or array of
> struct author that could be printed out at the end/before
> CAVEATS/BUGS et al.?

The canonical approach would be to use the syntax tree itself to
store the information and let the formatter decide what needs to
be printed at which time.  Usually, the formatter formats elements
in tree order, but it can (and already does) print some out of
order, earlier (or for AUTHORS, it would be later).  That implies
skipping the nodes when the normal tree walk comes across them and
explicitely accessing them from the place where they have to be
printed.

Another idea might be to insert a validation stage which could,
among other transformations, do reordering before starting the tree
walk for formatting.  Not sure yet whether that is a good idea -
it may be useful, even needed at some point, or it may turn out to
be overengineering...

> For now I'll put my <author> node in its own <refsect>.

I'm not sure i understand that sentence.  What do you mean with
"I'll put"?  Aren't DocBook elements part of input documents, and
aren't input documents things that are given a priori?  How can you
influence what is found in input documents?

Yours,
  Ingo
--
 To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH docbook2mdoc] Add NODE_EMAIL
  2019-03-23  8:46     ` Ingo Schwarze
@ 2019-03-23 10:18       ` Stephen Gregoratto
  2019-04-25 18:33         ` Ingo Schwarze
  0 siblings, 1 reply; 7+ messages in thread
From: Stephen Gregoratto @ 2019-03-23 10:18 UTC (permalink / raw)
  To: tech

On 2019-03-23 09:46, Ingo Schwarze wrote:
> I can't say i have ever *used* the DocBook format, but the man(7)
> output from DocBook files has struck me over and over again as the
> by far lowest quality man(7) code i have ever seen from any manual
> page generator.  DocBook is without any doubt the number one manual
> page generation scheme causing the most trouble in real life, in
> multiple respects.  By far.  So i am definitely not able to approach
> DocBook in good faith; i strongly hate DocBook and i am heavily
> biased against it based on previous experience.  But our different
> perspective on it can likely be productive.  :)

I believe you've mentioned this before on the markdown output article on 
undeadly.org. Actually that section at the end was the reason why I'm 
making these comparisons.

I forgot to mention that I'll be publishing my findings on my blog. I
aim to write up an example user command/library call man-page,
porting them by hand to the different formats. I'll describe the
methods/programs used to validate/format/convert each format, and
analyse the quality of the conversions. I'll also see how it fares
going through mandoc's HTML output, groff's PDF output and the UTF-8
output of both. Finally, I'll ask each respective "camp" if they'd
like to comment on my findings, and include them at the end (that
means you, Ingo). That's why I say good faith, I certainly don't want
to anger anyone from a different camp by hating their work right out
of the gate. That I can leave that up to you ;).
 
> I'm not sure i understand that sentence.  What do you mean with
> "I'll put"?  Aren't DocBook elements part of input documents, and
> aren't input documents things that are given a priori?  How can you
> influence what is found in input documents?

Whoops, forgot to put in the rest of the nodes. What I meant to say
was that I'll do this:

  <refsect1>
    <title>Authors</title>
    <para>The <command>foo</command> utility is maintained by
    <author>
      ...
    </author>.<para>
  </refsect1>
-- 
Stephen Gregoratto
PGP: 3FC6 3D0E 2801 C348 1C44 2D34 A80C 0F8E 8BAB EC8B
--
 To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH docbook2mdoc] Add NODE_EMAIL
  2019-03-23 10:18       ` Stephen Gregoratto
@ 2019-04-25 18:33         ` Ingo Schwarze
  0 siblings, 0 replies; 7+ messages in thread
From: Ingo Schwarze @ 2019-04-25 18:33 UTC (permalink / raw)
  To: Stephen Gregoratto; +Cc: tech

Hi Stephen,

Stephen Gregoratto wrote on Sat, Mar 23, 2019 at 09:18:35PM +1100:

> I forgot to mention that I'll be publishing my findings on my blog.
> I aim to write up an example user command/library call man-page,
> porting them by hand to the different formats. I'll describe the
> methods/programs used to validate/format/convert each format,

Sounds potentially interesting, but also a lot of work.

Many of the most important results are of course obvious from the
outset, for example than mdoc(7) and DocBook are semantically more
powerful than man(7), perlpod(1), Markdown, asciidoc and the like
and hence conversion quality will be strongly asymmetric in both
directions.  That doen't necessarily mean that you won't find any
non-trivial results, though.

> and analyse the quality of the conversions.

When analyzing validation and conversion quality, don't forget that
both validation and conversion can have very different objectives
and hence comparing them directly can be misleading.

For example, in mandoc(1) and in the default DocBook toolchain,
validation serves to help authors write good markup, whereas in
docbook2mdoc(1) it is only intended to help docbook2mdoc(1)
development.

For example, the DocBook to man(7) conversion in the default DocBook
toolchain, the perlpod(1) to man(7) conversion by pod2man(1), and
the mdoc(7) to HTML conversion by mandoc(1) are production conversions
that *every* document in the source languages is supposed to go
through, so they ought to be held to highest standards.  By contrast,
the mdoc(7) to man(7) and to markdown conversions in mandoc are
only auxiliary conversions to make the documents readable on inferior
systems or in constrained environments, so they ought to be held
to much lower standards; using them as a main production step wozuld
be a terrible idea in the first place.  And converters like pod2mdoc(1)
and doclifter(1) are only intended for one-time conversions with
manual postprocessing, so they should be held to an even lower
standard.  Conversion can have very different quality requirements.

> I'll also see how it fares going through mandoc's HTML output,
> groff's PDF output and the UTF-8 output of both.

The result of the latter cannot be tested with a single input file.
The output will likely be byte-by-byte identical, in particular
when you write good input code.

To compare the quality of groff and mandoc terminal output (including
ASCII or UTF-8), you need to compare large corpusses of documents
of diverse provinence, or the results won't be meaningful.

> Finally, I'll ask each respective "camp" if they'd
> like to comment on my findings, and include them at the end (that
> means you, Ingo).

Sure, ask me when you get to that point.

> That's why I say good faith, I certainly don't want
> to anger anyone from a different camp by hating their work right out
> of the gate. That I can leave that up to you ;).

Fine with me, i'll take care of that part.  :-)

Yours,
  Ingo
--
 To unsubscribe send an email to tech+unsubscribe@mandoc.bsd.lv

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2019-04-25 18:33 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-22 10:33 [PATCH docbook2mdoc] Add NODE_EMAIL Stephen Gregoratto
2019-03-22 12:32 ` Ingo Schwarze
2019-03-22 20:07 ` Ingo Schwarze
2019-03-23  5:30   ` Stephen Gregoratto
2019-03-23  8:46     ` Ingo Schwarze
2019-03-23 10:18       ` Stephen Gregoratto
2019-04-25 18:33         ` Ingo 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).