=================================================================== RCS file: /cvs/docbook2mdoc/node.c,v retrieving revision 1.3 retrieving revision 1.24 diff -u -p -r1.3 -r1.24 --- docbook2mdoc/node.c 2019/04/03 11:46:09 1.3 +++ docbook2mdoc/node.c 2019/04/28 15:03:29 1.24 @@ -1,4 +1,4 @@ -/* $Id: node.c,v 1.3 2019/04/03 11:46:09 schwarze Exp $ */ +/* $Id: node.c,v 1.24 2019/04/28 15:03:29 schwarze Exp $ */ /* * Copyright (c) 2014 Kristaps Dzonsons * Copyright (c) 2019 Ingo Schwarze @@ -15,33 +15,178 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include +#include "xmalloc.h" #include "node.h" /* * The implementation of the DocBook syntax tree. */ +struct nodeprop { + const char *name; + enum nodeclass class; +}; + +static const struct nodeprop properties[] = { + { "appendix", CLASS_BLOCK }, + { "arg", CLASS_ENCL }, + { "author", CLASS_LINE }, + { "authorgroup", CLASS_BLOCK }, + { "blockquote", CLASS_BLOCK }, + { "bookinfo", CLASS_BLOCK }, + { "caution", CLASS_BLOCK }, + { "citerefentry", CLASS_LINE }, + { "citetitle", CLASS_LINE }, + { "cmdsynopsis", CLASS_TRANS }, + { "colspec", CLASS_VOID }, + { "command", CLASS_LINE }, + { "constant", CLASS_LINE }, + { "contrib", CLASS_TRANS }, + { "copyright", CLASS_LINE }, + { "date", CLASS_TRANS }, + { "!DOCTYPE", CLASS_VOID }, + { "editor", CLASS_LINE }, + { "email", CLASS_ENCL }, + { "emphasis", CLASS_LINE }, + { "!ENTITY", CLASS_VOID }, + { "entry", CLASS_ENCL }, + { "envar", CLASS_LINE }, + { "errorname", CLASS_LINE }, + { "fieldsynopsis", CLASS_TRANS }, + { "filename", CLASS_LINE }, + { "firstterm", CLASS_LINE }, + { "footnote", CLASS_BLOCK }, + { "funcdef", CLASS_BLOCK }, + { "funcprototype", CLASS_BLOCK }, + { "funcsynopsis", CLASS_TRANS }, + { "funcsynopsisinfo", CLASS_LINE }, + { "function", CLASS_LINE }, + { "glossterm", CLASS_LINE }, + { "group", CLASS_ENCL }, + { "imagedata", CLASS_TEXT }, + { "xi:include", CLASS_VOID }, + { "index", CLASS_TRANS }, + { "info", CLASS_TRANS }, + { "informalequation", CLASS_BLOCK }, + { "inlineequation", CLASS_BLOCK }, + { "itemizedlist", CLASS_BLOCK }, + { "keysym", CLASS_LINE }, + { "legalnotice", CLASS_BLOCK }, + { "link", CLASS_ENCL }, + { "listitem", CLASS_TRANS }, + { "literal", CLASS_ENCL }, + { "literallayout", CLASS_NOFILL }, + { "manvolnum", CLASS_TRANS }, + { "markup", CLASS_LINE }, + { "member", CLASS_LINE }, + { "mml:math", CLASS_LINE }, + { "mml:mfenced", CLASS_LINE }, + { "mml:mfrac", CLASS_LINE }, + { "mml:mi", CLASS_LINE }, + { "mml:mn", CLASS_LINE }, + { "mml:mo", CLASS_LINE }, + { "mml:mrow", CLASS_LINE }, + { "mml:msub", CLASS_LINE }, + { "mml:msup", CLASS_LINE }, + { "modifier", CLASS_LINE }, + { "note", CLASS_BLOCK }, + { "olink", CLASS_ENCL }, + { "option", CLASS_LINE }, + { "orderedlist", CLASS_BLOCK }, + { "para", CLASS_BLOCK }, + { "paramdef", CLASS_LINE }, + { "parameter", CLASS_LINE }, + { "personname", CLASS_TRANS }, + { "preface", CLASS_BLOCK }, + { "productname", CLASS_LINE }, + { "programlisting", CLASS_NOFILL }, + { "prompt", CLASS_TRANS }, + { "pubdate", CLASS_TRANS }, + { "quote", CLASS_ENCL }, + { "refclass", CLASS_TRANS }, + { "refdescriptor", CLASS_TRANS }, + { "refentry", CLASS_TRANS }, + { "refentryinfo", CLASS_VOID }, + { "refentrytitle", CLASS_TRANS }, + { "refmeta", CLASS_TRANS }, + { "refmetainfo", CLASS_TRANS }, + { "refmiscinfo", CLASS_TRANS }, + { "refname", CLASS_LINE }, + { "refnamediv", CLASS_BLOCK }, + { "refpurpose", CLASS_LINE }, + { "refsynopsisdiv", CLASS_BLOCK }, + { "replaceable", CLASS_LINE }, + { "row", CLASS_BLOCK }, + { "sbr", CLASS_BLOCK }, + { "screen", CLASS_NOFILL }, + { "section", CLASS_BLOCK }, + { "simplelist", CLASS_TRANS }, + { "simplesect", CLASS_BLOCK }, + { "spanspec", CLASS_TRANS }, + { "subscript", CLASS_TEXT }, + { "subtitle", CLASS_BLOCK }, + { "superscript", CLASS_TEXT }, + { "synopsis", CLASS_NOFILL }, + { "systemitem", CLASS_LINE }, + { "table", CLASS_TRANS }, + { "tbody", CLASS_TRANS }, + { "term", CLASS_LINE }, + { "tfoot", CLASS_TRANS }, + { "tgroup", CLASS_BLOCK }, + { "thead", CLASS_TRANS }, + { "tip", CLASS_BLOCK }, + { "title", CLASS_BLOCK }, + { "type", CLASS_LINE }, + { "variablelist", CLASS_BLOCK }, + { "varlistentry", CLASS_BLOCK }, + { "varname", CLASS_LINE }, + { "void", CLASS_TEXT }, + { "warning", CLASS_BLOCK }, + { "wordasword", CLASS_TRANS }, + { "xref", CLASS_LINE }, + { "[UNKNOWN]", CLASS_VOID }, + { "(t)", CLASS_TEXT }, + { "(e)", CLASS_TEXT } +}; + static const char *const attrkeys[ATTRKEY__MAX] = { "choice", "class", "close", "cols", + "DEFINITION", + "endterm", + "entityref", + "fileref", + "href", "id", "linkend", + "localinfo", + "NAME", "open", - "rep" + "PUBLIC", + "rep", + "SYSTEM", + "targetdoc", + "targetptr", + "url", + "xlink:href" }; static const char *const attrvals[ATTRVAL__MAX] = { + "event", + "ipaddress", "monospaced", "norepeat", "opt", "plain", "repeat", - "req" + "req", + "systemname" }; enum attrkey @@ -55,6 +200,12 @@ attrkey_parse(const char *name) return key; } +const char * +attrkey_name(enum attrkey key) +{ + return attrkeys[key]; +} + enum attrval attrval_parse(const char *name) { @@ -66,52 +217,96 @@ attrval_parse(const char *name) return val; } +const char * +attr_getval(const struct pattr *a) +{ + return a->val == ATTRVAL__MAX ? a->rawval : attrvals[a->val]; +} + +enum nodeid +pnode_parse(const char *name) +{ + enum nodeid node; + + for (node = 0; node < NODE_UNKNOWN; node++) + if (strcmp(name, properties[node].name) == 0) + break; + return node; +} + +const char * +pnode_name(enum nodeid node) +{ + assert(node < NODE_IGNORE); + return properties[node].name; +} + +enum nodeclass +pnode_class(enum nodeid node) +{ + assert(node < NODE_IGNORE); + return properties[node].class; +} + +struct pnode * +pnode_alloc(struct pnode *np) +{ + struct pnode *n; + + n = xcalloc(1, sizeof(*n)); + TAILQ_INIT(&n->childq); + TAILQ_INIT(&n->attrq); + if ((n->parent = np) != NULL) + TAILQ_INSERT_TAIL(&np->childq, n, child); + return n; +} + /* * Recursively free a node (NULL is ok). */ static void -pnode_free(struct pnode *pn) +pnode_free(struct pnode *n) { - struct pnode *pch; - struct pattr *ap; + struct pnode *nc; + struct pattr *a; - if (pn == NULL) + if (n == NULL) return; - while ((pch = TAILQ_FIRST(&pn->childq)) != NULL) { - TAILQ_REMOVE(&pn->childq, pch, child); - pnode_free(pch); + while ((nc = TAILQ_FIRST(&n->childq)) != NULL) { + TAILQ_REMOVE(&n->childq, nc, child); + pnode_free(nc); } - while ((ap = TAILQ_FIRST(&pn->attrq)) != NULL) { - TAILQ_REMOVE(&pn->attrq, ap, child); - free(ap->rawval); - free(ap); + while ((a = TAILQ_FIRST(&n->attrq)) != NULL) { + TAILQ_REMOVE(&n->attrq, a, child); + free(a->rawval); + free(a); } - free(pn->real); - free(pn); + free(n->b); + free(n); } /* * Unlink a node from its parent and pnode_free() it. */ void -pnode_unlink(struct pnode *pn) +pnode_unlink(struct pnode *n) { - if (pn == NULL) + if (n == NULL) return; - if (pn->parent != NULL) - TAILQ_REMOVE(&pn->parent->childq, pn, child); - pnode_free(pn); + if (n->parent != NULL) + TAILQ_REMOVE(&n->parent->childq, n, child); + pnode_free(n); } /* * Unlink all children of a node and pnode_free() them. */ void -pnode_unlinksub(struct pnode *pn) +pnode_unlinksub(struct pnode *n) { - while (TAILQ_EMPTY(&pn->childq) == 0) - pnode_unlink(TAILQ_FIRST(&pn->childq)); + while (TAILQ_EMPTY(&n->childq) == 0) + pnode_unlink(TAILQ_FIRST(&n->childq)); } /* @@ -119,15 +314,15 @@ pnode_unlinksub(struct pnode *pn) * Return ATTRVAL__MAX if the node has no such attribute. */ enum attrval -pnode_getattr(struct pnode *pn, enum attrkey key) +pnode_getattr(struct pnode *n, enum attrkey key) { - struct pattr *ap; + struct pattr *a; - if (pn == NULL) + if (n == NULL) return ATTRVAL__MAX; - TAILQ_FOREACH(ap, &pn->attrq, child) - if (ap->key == key) - return ap->val; + TAILQ_FOREACH(a, &n->attrq, child) + if (a->key == key) + return a->val; return ATTRVAL__MAX; } @@ -136,16 +331,16 @@ pnode_getattr(struct pnode *pn, enum attrkey key) * Return defval if the node has no such attribute. */ const char * -pnode_getattr_raw(struct pnode *pn, enum attrkey key, const char *defval) +pnode_getattr_raw(struct pnode *n, enum attrkey key, const char *defval) { - struct pattr *ap; + struct pattr *a; - if (pn == NULL) + if (n == NULL) return defval; - TAILQ_FOREACH(ap, &pn->attrq, child) - if (ap->key == key) - return ap->val != ATTRVAL__MAX ? attrvals[ap->val] : - ap->rawval != NULL ? ap->rawval : defval; + TAILQ_FOREACH(a, &n->attrq, child) + if (a->key == key) + return a->val != ATTRVAL__MAX ? attrvals[a->val] : + a->rawval != NULL ? a->rawval : defval; return defval; } @@ -153,14 +348,29 @@ pnode_getattr_raw(struct pnode *pn, enum attrkey key, * Recursively search and return the first instance of "node". */ struct pnode * -pnode_findfirst(struct pnode *pn, enum nodeid node) +pnode_findfirst(struct pnode *n, enum nodeid node) { - struct pnode *pch, *res; + struct pnode *nc, *res; - if (pn->node == node) - return pn; - TAILQ_FOREACH(pch, &pn->childq, child) - if ((res = pnode_findfirst(pch, node)) != NULL) + if (n == NULL) + return NULL; + if (n->node == node) + return n; + TAILQ_FOREACH(nc, &n->childq, child) + if ((res = pnode_findfirst(nc, node)) != NULL) return res; return NULL; +} + +/* + * Like pnode_findfirst(), but also take the node out of the tree. + */ +struct pnode * +pnode_takefirst(struct pnode *n, enum nodeid node) +{ + struct pnode *nc; + + if ((nc = pnode_findfirst(n, node)) != NULL && nc->parent != NULL) + TAILQ_REMOVE(&nc->parent->childq, nc, child); + return nc; }