version 1.4, 2019/04/07 17:00:56 |
version 1.24, 2019/04/28 15:03:29 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
*/ |
|
#include <assert.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
|
|
#include "xmalloc.h" |
#include "node.h" |
#include "node.h" |
|
|
/* |
/* |
* The implementation of the DocBook syntax tree. |
* 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] = { |
static const char *const attrkeys[ATTRKEY__MAX] = { |
"choice", |
"choice", |
"class", |
"class", |
"close", |
"close", |
"cols", |
"cols", |
|
"DEFINITION", |
"endterm", |
"endterm", |
|
"entityref", |
|
"fileref", |
|
"href", |
"id", |
"id", |
"linkend", |
"linkend", |
|
"localinfo", |
|
"NAME", |
"open", |
"open", |
|
"PUBLIC", |
"rep", |
"rep", |
|
"SYSTEM", |
|
"targetdoc", |
|
"targetptr", |
"url", |
"url", |
"xlink:href" |
"xlink:href" |
}; |
}; |
|
|
static const char *const attrvals[ATTRVAL__MAX] = { |
static const char *const attrvals[ATTRVAL__MAX] = { |
|
"event", |
|
"ipaddress", |
"monospaced", |
"monospaced", |
"norepeat", |
"norepeat", |
"opt", |
"opt", |
"plain", |
"plain", |
"repeat", |
"repeat", |
"req" |
"req", |
|
"systemname" |
}; |
}; |
|
|
enum attrkey |
enum attrkey |
Line 58 attrkey_parse(const char *name) |
|
Line 200 attrkey_parse(const char *name) |
|
return key; |
return key; |
} |
} |
|
|
|
const char * |
|
attrkey_name(enum attrkey key) |
|
{ |
|
return attrkeys[key]; |
|
} |
|
|
enum attrval |
enum attrval |
attrval_parse(const char *name) |
attrval_parse(const char *name) |
{ |
{ |
Line 69 attrval_parse(const char *name) |
|
Line 217 attrval_parse(const char *name) |
|
return val; |
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). |
* Recursively free a node (NULL is ok). |
*/ |
*/ |
static void |
static void |
pnode_free(struct pnode *pn) |
pnode_free(struct pnode *n) |
{ |
{ |
struct pnode *pch; |
struct pnode *nc; |
struct pattr *ap; |
struct pattr *a; |
|
|
if (pn == NULL) |
if (n == NULL) |
return; |
return; |
|
|
while ((pch = TAILQ_FIRST(&pn->childq)) != NULL) { |
while ((nc = TAILQ_FIRST(&n->childq)) != NULL) { |
TAILQ_REMOVE(&pn->childq, pch, child); |
TAILQ_REMOVE(&n->childq, nc, child); |
pnode_free(pch); |
pnode_free(nc); |
} |
} |
while ((ap = TAILQ_FIRST(&pn->attrq)) != NULL) { |
while ((a = TAILQ_FIRST(&n->attrq)) != NULL) { |
TAILQ_REMOVE(&pn->attrq, ap, child); |
TAILQ_REMOVE(&n->attrq, a, child); |
free(ap->rawval); |
free(a->rawval); |
free(ap); |
free(a); |
} |
} |
free(pn->real); |
free(n->b); |
free(pn); |
free(n); |
} |
} |
|
|
/* |
/* |
* Unlink a node from its parent and pnode_free() it. |
* Unlink a node from its parent and pnode_free() it. |
*/ |
*/ |
void |
void |
pnode_unlink(struct pnode *pn) |
pnode_unlink(struct pnode *n) |
{ |
{ |
if (pn == NULL) |
if (n == NULL) |
return; |
return; |
if (pn->parent != NULL) |
if (n->parent != NULL) |
TAILQ_REMOVE(&pn->parent->childq, pn, child); |
TAILQ_REMOVE(&n->parent->childq, n, child); |
pnode_free(pn); |
pnode_free(n); |
} |
} |
|
|
/* |
/* |
* Unlink all children of a node and pnode_free() them. |
* Unlink all children of a node and pnode_free() them. |
*/ |
*/ |
void |
void |
pnode_unlinksub(struct pnode *pn) |
pnode_unlinksub(struct pnode *n) |
{ |
{ |
while (TAILQ_EMPTY(&pn->childq) == 0) |
while (TAILQ_EMPTY(&n->childq) == 0) |
pnode_unlink(TAILQ_FIRST(&pn->childq)); |
pnode_unlink(TAILQ_FIRST(&n->childq)); |
} |
} |
|
|
/* |
/* |
Line 122 pnode_unlinksub(struct pnode *pn) |
|
Line 314 pnode_unlinksub(struct pnode *pn) |
|
* Return ATTRVAL__MAX if the node has no such attribute. |
* Return ATTRVAL__MAX if the node has no such attribute. |
*/ |
*/ |
enum attrval |
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; |
return ATTRVAL__MAX; |
TAILQ_FOREACH(ap, &pn->attrq, child) |
TAILQ_FOREACH(a, &n->attrq, child) |
if (ap->key == key) |
if (a->key == key) |
return ap->val; |
return a->val; |
return ATTRVAL__MAX; |
return ATTRVAL__MAX; |
} |
} |
|
|
Line 139 pnode_getattr(struct pnode *pn, enum attrkey key) |
|
Line 331 pnode_getattr(struct pnode *pn, enum attrkey key) |
|
* Return defval if the node has no such attribute. |
* Return defval if the node has no such attribute. |
*/ |
*/ |
const char * |
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; |
return defval; |
TAILQ_FOREACH(ap, &pn->attrq, child) |
TAILQ_FOREACH(a, &n->attrq, child) |
if (ap->key == key) |
if (a->key == key) |
return ap->val != ATTRVAL__MAX ? attrvals[ap->val] : |
return a->val != ATTRVAL__MAX ? attrvals[a->val] : |
ap->rawval != NULL ? ap->rawval : defval; |
a->rawval != NULL ? a->rawval : defval; |
return defval; |
return defval; |
} |
} |
|
|
Line 156 pnode_getattr_raw(struct pnode *pn, enum attrkey key, |
|
Line 348 pnode_getattr_raw(struct pnode *pn, enum attrkey key, |
|
* Recursively search and return the first instance of "node". |
* Recursively search and return the first instance of "node". |
*/ |
*/ |
struct pnode * |
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) |
if (n == NULL) |
return pn; |
return NULL; |
TAILQ_FOREACH(pch, &pn->childq, child) |
if (n->node == node) |
if ((res = pnode_findfirst(pch, node)) != NULL) |
return n; |
|
TAILQ_FOREACH(nc, &n->childq, child) |
|
if ((res = pnode_findfirst(nc, node)) != NULL) |
return res; |
return res; |
return NULL; |
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; |
} |
} |