Annotation of docbook2mdoc/node.c, Revision 1.10
1.10 ! schwarze 1: /* $Id: node.c,v 1.9 2019/04/12 04:39:24 schwarze Exp $ */
1.1 schwarze 2: /*
3: * Copyright (c) 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4: * Copyright (c) 2019 Ingo Schwarze <schwarze@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
1.10 ! schwarze 18: #include <assert.h>
1.1 schwarze 19: #include <stdlib.h>
20: #include <string.h>
21:
22: #include "node.h"
23:
24: /*
25: * The implementation of the DocBook syntax tree.
26: */
27:
1.10 ! schwarze 28: struct nodeprop {
! 29: const char *name;
! 30: enum nodeclass class;
! 31: };
! 32:
! 33: static const struct nodeprop properties[] = {
! 34: { "affiliation", CLASS_TRANS },
! 35: { "appendix", CLASS_BLOCK },
! 36: { "application", CLASS_LINE },
! 37: { "arg", CLASS_ENCL },
! 38: { "author", CLASS_LINE },
! 39: { "authorgroup", CLASS_BLOCK },
! 40: { "blockquote", CLASS_BLOCK },
! 41: { "bookinfo", CLASS_BLOCK },
! 42: { "caution", CLASS_BLOCK },
! 43: { "citerefentry", CLASS_LINE },
! 44: { "citetitle", CLASS_LINE },
! 45: { "cmdsynopsis", CLASS_TRANS },
! 46: { "colspec", CLASS_VOID },
! 47: { "command", CLASS_LINE },
! 48: { "constant", CLASS_LINE },
! 49: { "contrib", CLASS_TRANS },
! 50: { "copyright", CLASS_TRANS },
! 51: { "date", CLASS_TRANS },
! 52: { "!DOCTYPE", CLASS_VOID },
! 53: { "editor", CLASS_LINE },
! 54: { "email", CLASS_ENCL },
! 55: { "emphasis", CLASS_LINE },
! 56: { "!ENTITY", CLASS_VOID },
! 57: { "entry", CLASS_ENCL },
! 58: { "envar", CLASS_LINE },
! 59: { "errorname", CLASS_LINE },
! 60: { "fieldsynopsis", CLASS_TRANS },
! 61: { "filename", CLASS_LINE },
! 62: { "firstterm", CLASS_LINE },
! 63: { "footnote", CLASS_TRANS },
! 64: { "funcdef", CLASS_BLOCK },
! 65: { "funcprototype", CLASS_BLOCK },
! 66: { "funcsynopsis", CLASS_TRANS },
! 67: { "funcsynopsisinfo", CLASS_LINE },
! 68: { "function", CLASS_LINE },
! 69: { "glossterm", CLASS_LINE },
! 70: { "group", CLASS_ENCL },
! 71: { "holder", CLASS_TRANS },
! 72: { "xi:include", CLASS_VOID },
! 73: { "index", CLASS_TRANS },
! 74: { "info", CLASS_TRANS },
! 75: { "informalequation", CLASS_BLOCK },
! 76: { "inlineequation", CLASS_BLOCK },
! 77: { "itemizedlist", CLASS_BLOCK },
! 78: { "keysym", CLASS_LINE },
! 79: { "legalnotice", CLASS_BLOCK },
! 80: { "link", CLASS_ENCL },
! 81: { "listitem", CLASS_TRANS },
! 82: { "literal", CLASS_ENCL },
! 83: { "literallayout", CLASS_BLOCK },
! 84: { "manvolnum", CLASS_TRANS },
! 85: { "markup", CLASS_LINE },
! 86: { "member", CLASS_LINE },
! 87: { "mml:math", CLASS_LINE },
! 88: { "mml:mfenced", CLASS_LINE },
! 89: { "mml:mfrac", CLASS_LINE },
! 90: { "mml:mi", CLASS_LINE },
! 91: { "mml:mn", CLASS_LINE },
! 92: { "mml:mo", CLASS_LINE },
! 93: { "mml:mrow", CLASS_LINE },
! 94: { "mml:msub", CLASS_LINE },
! 95: { "mml:msup", CLASS_LINE },
! 96: { "modifier", CLASS_LINE },
! 97: { "note", CLASS_BLOCK },
! 98: { "option", CLASS_LINE },
! 99: { "orderedlist", CLASS_BLOCK },
! 100: { "orgname", CLASS_TRANS },
! 101: { "para", CLASS_BLOCK },
! 102: { "paramdef", CLASS_LINE },
! 103: { "parameter", CLASS_LINE },
! 104: { "personname", CLASS_TRANS },
! 105: { "preface", CLASS_BLOCK },
! 106: { "programlisting", CLASS_BLOCK },
! 107: { "prompt", CLASS_TRANS },
! 108: { "quote", CLASS_ENCL },
! 109: { "refclass", CLASS_TRANS },
! 110: { "refdescriptor", CLASS_TRANS },
! 111: { "refentry", CLASS_TRANS },
! 112: { "refentryinfo", CLASS_VOID },
! 113: { "refentrytitle", CLASS_TRANS },
! 114: { "refmeta", CLASS_TRANS },
! 115: { "refmetainfo", CLASS_TRANS },
! 116: { "refmiscinfo", CLASS_TRANS },
! 117: { "refname", CLASS_LINE },
! 118: { "refnamediv", CLASS_BLOCK },
! 119: { "refpurpose", CLASS_LINE },
! 120: { "refsynopsisdiv", CLASS_BLOCK },
! 121: { "releaseinfo", CLASS_TRANS },
! 122: { "replaceable", CLASS_LINE },
! 123: { "row", CLASS_BLOCK },
! 124: { "sbr", CLASS_BLOCK },
! 125: { "screen", CLASS_BLOCK },
! 126: { "section", CLASS_BLOCK },
! 127: { "simplelist", CLASS_TRANS },
! 128: { "spanspec", CLASS_TRANS },
! 129: { "subtitle", CLASS_TRANS },
! 130: { "synopsis", CLASS_BLOCK },
! 131: { "table", CLASS_TRANS },
! 132: { "tbody", CLASS_TRANS },
! 133: { "term", CLASS_LINE },
! 134: { "tfoot", CLASS_TRANS },
! 135: { "tgroup", CLASS_BLOCK },
! 136: { "thead", CLASS_TRANS },
! 137: { "tip", CLASS_BLOCK },
! 138: { "title", CLASS_BLOCK },
! 139: { "type", CLASS_LINE },
! 140: { "variablelist", CLASS_BLOCK },
! 141: { "varlistentry", CLASS_BLOCK },
! 142: { "varname", CLASS_LINE },
! 143: { "warning", CLASS_BLOCK },
! 144: { "wordasword", CLASS_TRANS },
! 145: { "year", CLASS_TRANS },
! 146: { "[UNKNOWN]", CLASS_VOID },
! 147: { "[TEXT]", CLASS_TEXT },
! 148: { "[ESCAPE]", CLASS_TEXT }
! 149: };
! 150:
1.1 schwarze 151: static const char *const attrkeys[ATTRKEY__MAX] = {
152: "choice",
153: "class",
154: "close",
1.3 schwarze 155: "cols",
1.5 schwarze 156: "DEFINITION",
1.4 schwarze 157: "endterm",
1.6 schwarze 158: "href",
1.1 schwarze 159: "id",
160: "linkend",
1.5 schwarze 161: "NAME",
1.1 schwarze 162: "open",
1.5 schwarze 163: "PUBLIC",
1.4 schwarze 164: "rep",
1.5 schwarze 165: "SYSTEM",
1.4 schwarze 166: "url",
167: "xlink:href"
1.1 schwarze 168: };
169:
170: static const char *const attrvals[ATTRVAL__MAX] = {
171: "monospaced",
172: "norepeat",
173: "opt",
174: "plain",
175: "repeat",
176: "req"
177: };
178:
179: enum attrkey
180: attrkey_parse(const char *name)
181: {
182: enum attrkey key;
183:
184: for (key = 0; key < ATTRKEY__MAX; key++)
185: if (strcmp(name, attrkeys[key]) == 0)
186: break;
187: return key;
188: }
189:
190: enum attrval
191: attrval_parse(const char *name)
192: {
193: enum attrval val;
194:
195: for (val = 0; val < ATTRVAL__MAX; val++)
196: if (strcmp(name, attrvals[val]) == 0)
197: break;
198: return val;
1.10 ! schwarze 199: }
! 200:
! 201: enum nodeid
! 202: pnode_parse(const char *name)
! 203: {
! 204: enum nodeid node;
! 205:
! 206: for (node = 0; node < NODE_UNKNOWN; node++)
! 207: if (strcmp(name, properties[node].name) == 0)
! 208: break;
! 209: return node;
! 210: }
! 211:
! 212: const char *
! 213: pnode_name(enum nodeid node)
! 214: {
! 215: assert(node < NODE_IGNORE);
! 216: return properties[node].name;
! 217: }
! 218:
! 219: enum nodeclass
! 220: pnode_class(enum nodeid node)
! 221: {
! 222: assert(node < NODE_IGNORE);
! 223: return properties[node].class;
1.9 schwarze 224: }
225:
226: struct pnode *
227: pnode_alloc(struct pnode *np)
228: {
229: struct pnode *n;
230:
231: if ((n = calloc(1, sizeof(*n))) != NULL) {
232: TAILQ_INIT(&n->childq);
233: TAILQ_INIT(&n->attrq);
234: if ((n->parent = np) != NULL)
235: TAILQ_INSERT_TAIL(&np->childq, n, child);
236: }
237: return n;
1.1 schwarze 238: }
239:
240: /*
241: * Recursively free a node (NULL is ok).
242: */
243: static void
1.7 schwarze 244: pnode_free(struct pnode *n)
1.1 schwarze 245: {
1.7 schwarze 246: struct pnode *nc;
247: struct pattr *a;
1.1 schwarze 248:
1.7 schwarze 249: if (n == NULL)
1.1 schwarze 250: return;
251:
1.7 schwarze 252: while ((nc = TAILQ_FIRST(&n->childq)) != NULL) {
253: TAILQ_REMOVE(&n->childq, nc, child);
254: pnode_free(nc);
1.1 schwarze 255: }
1.7 schwarze 256: while ((a = TAILQ_FIRST(&n->attrq)) != NULL) {
257: TAILQ_REMOVE(&n->attrq, a, child);
258: free(a->rawval);
259: free(a);
1.1 schwarze 260: }
1.8 schwarze 261: free(n->b);
1.7 schwarze 262: free(n);
1.1 schwarze 263: }
264:
265: /*
266: * Unlink a node from its parent and pnode_free() it.
267: */
268: void
1.7 schwarze 269: pnode_unlink(struct pnode *n)
1.1 schwarze 270: {
1.7 schwarze 271: if (n == NULL)
1.1 schwarze 272: return;
1.7 schwarze 273: if (n->parent != NULL)
274: TAILQ_REMOVE(&n->parent->childq, n, child);
275: pnode_free(n);
1.1 schwarze 276: }
277:
278: /*
279: * Unlink all children of a node and pnode_free() them.
280: */
281: void
1.7 schwarze 282: pnode_unlinksub(struct pnode *n)
1.1 schwarze 283: {
1.7 schwarze 284: while (TAILQ_EMPTY(&n->childq) == 0)
285: pnode_unlink(TAILQ_FIRST(&n->childq));
1.1 schwarze 286: }
287:
288: /*
289: * Retrieve an enumeration attribute from a node.
290: * Return ATTRVAL__MAX if the node has no such attribute.
291: */
292: enum attrval
1.7 schwarze 293: pnode_getattr(struct pnode *n, enum attrkey key)
1.1 schwarze 294: {
1.7 schwarze 295: struct pattr *a;
1.1 schwarze 296:
1.7 schwarze 297: if (n == NULL)
1.1 schwarze 298: return ATTRVAL__MAX;
1.7 schwarze 299: TAILQ_FOREACH(a, &n->attrq, child)
300: if (a->key == key)
301: return a->val;
1.1 schwarze 302: return ATTRVAL__MAX;
303: }
304:
305: /*
306: * Retrieve an attribute string from a node.
307: * Return defval if the node has no such attribute.
308: */
309: const char *
1.7 schwarze 310: pnode_getattr_raw(struct pnode *n, enum attrkey key, const char *defval)
1.1 schwarze 311: {
1.7 schwarze 312: struct pattr *a;
1.1 schwarze 313:
1.7 schwarze 314: if (n == NULL)
1.1 schwarze 315: return defval;
1.7 schwarze 316: TAILQ_FOREACH(a, &n->attrq, child)
317: if (a->key == key)
318: return a->val != ATTRVAL__MAX ? attrvals[a->val] :
319: a->rawval != NULL ? a->rawval : defval;
1.1 schwarze 320: return defval;
321: }
322:
323: /*
324: * Recursively search and return the first instance of "node".
325: */
326: struct pnode *
1.7 schwarze 327: pnode_findfirst(struct pnode *n, enum nodeid node)
1.1 schwarze 328: {
1.7 schwarze 329: struct pnode *nc, *res;
1.1 schwarze 330:
1.7 schwarze 331: if (n->node == node)
332: return n;
333: TAILQ_FOREACH(nc, &n->childq, child)
334: if ((res = pnode_findfirst(nc, node)) != NULL)
1.1 schwarze 335: return res;
336: return NULL;
337: }
CVSweb