tech@mandoc.bsd.lv
 help / color / mirror / Atom feed
From: Ingo Schwarze <schwarze@usta.de>
To: kristaps@bsd.lv
Cc: tech@mandoc.bsd.lv, Stephen Gregoratto <dev@sgregoratto.me>
Subject: Re: [PATCH docbook2mdoc] Add NODE_EMAIL
Date: Fri, 22 Mar 2019 13:32:34 +0100	[thread overview]
Message-ID: <20190322123234.GA6535@athene.usta.de> (raw)
In-Reply-To: <20190322103342.6idzehqruirutcog@BlackBox>

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

  reply	other threads:[~2019-03-22 12:32 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-22 10:33 Stephen Gregoratto
2019-03-22 12:32 ` Ingo Schwarze [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190322123234.GA6535@athene.usta.de \
    --to=schwarze@usta.de \
    --cc=dev@sgregoratto.me \
    --cc=kristaps@bsd.lv \
    --cc=tech@mandoc.bsd.lv \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).