/* $Id: node.c,v 1.4 2019/04/07 17:00:56 schwarze Exp $ */ /* * Copyright (c) 2014 Kristaps Dzonsons * Copyright (c) 2019 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * 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 "node.h" /* * The implementation of the DocBook syntax tree. */ static const char *const attrkeys[ATTRKEY__MAX] = { "choice", "class", "close", "cols", "endterm", "id", "linkend", "open", "rep", "url", "xlink:href" }; static const char *const attrvals[ATTRVAL__MAX] = { "monospaced", "norepeat", "opt", "plain", "repeat", "req" }; enum attrkey attrkey_parse(const char *name) { enum attrkey key; for (key = 0; key < ATTRKEY__MAX; key++) if (strcmp(name, attrkeys[key]) == 0) break; return key; } enum attrval attrval_parse(const char *name) { enum attrval val; for (val = 0; val < ATTRVAL__MAX; val++) if (strcmp(name, attrvals[val]) == 0) break; return val; } /* * Recursively free a node (NULL is ok). */ static void pnode_free(struct pnode *pn) { struct pnode *pch; struct pattr *ap; if (pn == NULL) return; while ((pch = TAILQ_FIRST(&pn->childq)) != NULL) { TAILQ_REMOVE(&pn->childq, pch, child); pnode_free(pch); } while ((ap = TAILQ_FIRST(&pn->attrq)) != NULL) { TAILQ_REMOVE(&pn->attrq, ap, child); free(ap->rawval); free(ap); } free(pn->real); free(pn); } /* * Unlink a node from its parent and pnode_free() it. */ void pnode_unlink(struct pnode *pn) { if (pn == NULL) return; if (pn->parent != NULL) TAILQ_REMOVE(&pn->parent->childq, pn, child); pnode_free(pn); } /* * Unlink all children of a node and pnode_free() them. */ void pnode_unlinksub(struct pnode *pn) { while (TAILQ_EMPTY(&pn->childq) == 0) pnode_unlink(TAILQ_FIRST(&pn->childq)); } /* * Retrieve an enumeration attribute from a node. * Return ATTRVAL__MAX if the node has no such attribute. */ enum attrval pnode_getattr(struct pnode *pn, enum attrkey key) { struct pattr *ap; if (pn == NULL) return ATTRVAL__MAX; TAILQ_FOREACH(ap, &pn->attrq, child) if (ap->key == key) return ap->val; return ATTRVAL__MAX; } /* * Retrieve an attribute string from a node. * Return defval if the node has no such attribute. */ const char * pnode_getattr_raw(struct pnode *pn, enum attrkey key, const char *defval) { struct pattr *ap; if (pn == 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; return defval; } /* * Recursively search and return the first instance of "node". */ struct pnode * pnode_findfirst(struct pnode *pn, enum nodeid node) { struct pnode *pch, *res; if (pn->node == node) return pn; TAILQ_FOREACH(pch, &pn->childq, child) if ((res = pnode_findfirst(pch, node)) != NULL) return res; return NULL; }