/* $Id: node.c,v 1.9 2019/04/12 04:39:24 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", "DEFINITION", "endterm", "href", "id", "linkend", "NAME", "open", "PUBLIC", "rep", "SYSTEM", "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; } struct pnode * pnode_alloc(struct pnode *np) { struct pnode *n; if ((n = calloc(1, sizeof(*n))) != NULL) { 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 *n) { struct pnode *nc; struct pattr *a; if (n == NULL) return; while ((nc = TAILQ_FIRST(&n->childq)) != NULL) { TAILQ_REMOVE(&n->childq, nc, child); pnode_free(nc); } while ((a = TAILQ_FIRST(&n->attrq)) != NULL) { TAILQ_REMOVE(&n->attrq, a, child); free(a->rawval); free(a); } free(n->b); free(n); } /* * Unlink a node from its parent and pnode_free() it. */ void pnode_unlink(struct pnode *n) { if (n == NULL) return; 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 *n) { while (TAILQ_EMPTY(&n->childq) == 0) pnode_unlink(TAILQ_FIRST(&n->childq)); } /* * Retrieve an enumeration attribute from a node. * Return ATTRVAL__MAX if the node has no such attribute. */ enum attrval pnode_getattr(struct pnode *n, enum attrkey key) { struct pattr *a; if (n == NULL) return ATTRVAL__MAX; TAILQ_FOREACH(a, &n->attrq, child) if (a->key == key) return a->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 *n, enum attrkey key, const char *defval) { struct pattr *a; if (n == NULL) return 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; } /* * Recursively search and return the first instance of "node". */ struct pnode * pnode_findfirst(struct pnode *n, enum nodeid node) { struct pnode *nc, *res; if (n->node == node) return n; TAILQ_FOREACH(nc, &n->childq, child) if ((res = pnode_findfirst(nc, node)) != NULL) return res; return NULL; }