Annotation of docbook2mdoc/node.c, Revision 1.28
1.28 ! schwarze 1: /* $Id: node.c,v 1.27 2019/05/01 11:34:20 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:
1.24 schwarze 22: #include "xmalloc.h"
1.1 schwarze 23: #include "node.h"
24:
25: /*
26: * The implementation of the DocBook syntax tree.
27: */
28:
1.10 schwarze 29: struct nodeprop {
30: const char *name;
31: enum nodeclass class;
32: };
33:
34: static const struct nodeprop properties[] = {
1.26 schwarze 35: { "abstract", CLASS_BLOCK },
1.10 schwarze 36: { "appendix", CLASS_BLOCK },
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 },
1.15 schwarze 50: { "copyright", CLASS_LINE },
1.10 schwarze 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 },
1.17 schwarze 63: { "footnote", CLASS_BLOCK },
1.10 schwarze 64: { "funcdef", CLASS_BLOCK },
1.28 ! schwarze 65: { "funcparams", CLASS_LINE },
1.10 schwarze 66: { "funcprototype", CLASS_BLOCK },
67: { "funcsynopsis", CLASS_TRANS },
68: { "funcsynopsisinfo", CLASS_LINE },
69: { "function", CLASS_LINE },
70: { "glossterm", CLASS_LINE },
71: { "group", CLASS_ENCL },
1.18 schwarze 72: { "imagedata", CLASS_TEXT },
1.10 schwarze 73: { "xi:include", CLASS_VOID },
74: { "index", CLASS_TRANS },
75: { "info", CLASS_TRANS },
76: { "informalequation", CLASS_BLOCK },
77: { "inlineequation", CLASS_BLOCK },
78: { "itemizedlist", CLASS_BLOCK },
79: { "keysym", CLASS_LINE },
80: { "legalnotice", CLASS_BLOCK },
81: { "link", CLASS_ENCL },
82: { "listitem", CLASS_TRANS },
83: { "literal", CLASS_ENCL },
1.21 schwarze 84: { "literallayout", CLASS_NOFILL },
1.10 schwarze 85: { "manvolnum", CLASS_TRANS },
86: { "markup", CLASS_LINE },
87: { "member", CLASS_LINE },
88: { "mml:math", CLASS_LINE },
89: { "mml:mfenced", CLASS_LINE },
90: { "mml:mfrac", CLASS_LINE },
91: { "mml:mi", CLASS_LINE },
92: { "mml:mn", CLASS_LINE },
93: { "mml:mo", CLASS_LINE },
94: { "mml:mrow", CLASS_LINE },
95: { "mml:msub", CLASS_LINE },
96: { "mml:msup", CLASS_LINE },
97: { "modifier", CLASS_LINE },
98: { "note", CLASS_BLOCK },
1.19 schwarze 99: { "olink", CLASS_ENCL },
1.10 schwarze 100: { "option", CLASS_LINE },
101: { "orderedlist", CLASS_BLOCK },
102: { "para", CLASS_BLOCK },
103: { "paramdef", CLASS_LINE },
104: { "parameter", CLASS_LINE },
105: { "personname", CLASS_TRANS },
106: { "preface", CLASS_BLOCK },
1.22 schwarze 107: { "productname", CLASS_LINE },
1.21 schwarze 108: { "programlisting", CLASS_NOFILL },
1.10 schwarze 109: { "prompt", CLASS_TRANS },
1.12 schwarze 110: { "pubdate", CLASS_TRANS },
1.10 schwarze 111: { "quote", CLASS_ENCL },
112: { "refclass", CLASS_TRANS },
113: { "refdescriptor", CLASS_TRANS },
114: { "refentry", CLASS_TRANS },
115: { "refentryinfo", CLASS_VOID },
116: { "refentrytitle", CLASS_TRANS },
117: { "refmeta", CLASS_TRANS },
118: { "refmetainfo", CLASS_TRANS },
119: { "refmiscinfo", CLASS_TRANS },
120: { "refname", CLASS_LINE },
121: { "refnamediv", CLASS_BLOCK },
122: { "refpurpose", CLASS_LINE },
123: { "refsynopsisdiv", CLASS_BLOCK },
124: { "replaceable", CLASS_LINE },
125: { "row", CLASS_BLOCK },
126: { "sbr", CLASS_BLOCK },
1.21 schwarze 127: { "screen", CLASS_NOFILL },
1.10 schwarze 128: { "section", CLASS_BLOCK },
129: { "simplelist", CLASS_TRANS },
1.15 schwarze 130: { "simplesect", CLASS_BLOCK },
1.10 schwarze 131: { "spanspec", CLASS_TRANS },
1.16 schwarze 132: { "subscript", CLASS_TEXT },
1.15 schwarze 133: { "subtitle", CLASS_BLOCK },
1.16 schwarze 134: { "superscript", CLASS_TEXT },
1.21 schwarze 135: { "synopsis", CLASS_NOFILL },
1.13 schwarze 136: { "systemitem", CLASS_LINE },
1.10 schwarze 137: { "table", CLASS_TRANS },
138: { "tbody", CLASS_TRANS },
139: { "term", CLASS_LINE },
140: { "tfoot", CLASS_TRANS },
141: { "tgroup", CLASS_BLOCK },
142: { "thead", CLASS_TRANS },
143: { "tip", CLASS_BLOCK },
144: { "title", CLASS_BLOCK },
145: { "type", CLASS_LINE },
146: { "variablelist", CLASS_BLOCK },
147: { "varlistentry", CLASS_BLOCK },
148: { "varname", CLASS_LINE },
1.23 schwarze 149: { "void", CLASS_TEXT },
1.10 schwarze 150: { "warning", CLASS_BLOCK },
151: { "wordasword", CLASS_TRANS },
1.20 schwarze 152: { "xref", CLASS_LINE },
1.27 schwarze 153: { "year", CLASS_TRANS },
1.10 schwarze 154: { "[UNKNOWN]", CLASS_VOID },
1.11 schwarze 155: { "(t)", CLASS_TEXT },
156: { "(e)", CLASS_TEXT }
1.10 schwarze 157: };
158:
1.1 schwarze 159: static const char *const attrkeys[ATTRKEY__MAX] = {
160: "choice",
161: "class",
162: "close",
1.3 schwarze 163: "cols",
1.5 schwarze 164: "DEFINITION",
1.4 schwarze 165: "endterm",
1.18 schwarze 166: "entityref",
167: "fileref",
1.6 schwarze 168: "href",
1.1 schwarze 169: "id",
170: "linkend",
1.19 schwarze 171: "localinfo",
1.5 schwarze 172: "NAME",
1.1 schwarze 173: "open",
1.5 schwarze 174: "PUBLIC",
1.4 schwarze 175: "rep",
1.5 schwarze 176: "SYSTEM",
1.19 schwarze 177: "targetdoc",
178: "targetptr",
1.4 schwarze 179: "url",
180: "xlink:href"
1.1 schwarze 181: };
182:
183: static const char *const attrvals[ATTRVAL__MAX] = {
1.13 schwarze 184: "event",
185: "ipaddress",
1.1 schwarze 186: "monospaced",
187: "norepeat",
188: "opt",
189: "plain",
190: "repeat",
1.13 schwarze 191: "req",
192: "systemname"
1.1 schwarze 193: };
194:
195: enum attrkey
196: attrkey_parse(const char *name)
197: {
198: enum attrkey key;
199:
200: for (key = 0; key < ATTRKEY__MAX; key++)
201: if (strcmp(name, attrkeys[key]) == 0)
202: break;
203: return key;
204: }
205:
1.11 schwarze 206: const char *
207: attrkey_name(enum attrkey key)
208: {
209: return attrkeys[key];
210: }
211:
1.1 schwarze 212: enum attrval
213: attrval_parse(const char *name)
214: {
215: enum attrval val;
216:
217: for (val = 0; val < ATTRVAL__MAX; val++)
218: if (strcmp(name, attrvals[val]) == 0)
219: break;
220: return val;
1.11 schwarze 221: }
222:
223: const char *
224: attr_getval(const struct pattr *a)
225: {
226: return a->val == ATTRVAL__MAX ? a->rawval : attrvals[a->val];
1.10 schwarze 227: }
228:
229: enum nodeid
230: pnode_parse(const char *name)
231: {
232: enum nodeid node;
233:
234: for (node = 0; node < NODE_UNKNOWN; node++)
235: if (strcmp(name, properties[node].name) == 0)
236: break;
237: return node;
238: }
239:
240: const char *
241: pnode_name(enum nodeid node)
242: {
243: assert(node < NODE_IGNORE);
244: return properties[node].name;
245: }
246:
247: enum nodeclass
248: pnode_class(enum nodeid node)
249: {
250: assert(node < NODE_IGNORE);
251: return properties[node].class;
1.9 schwarze 252: }
253:
254: struct pnode *
255: pnode_alloc(struct pnode *np)
256: {
257: struct pnode *n;
258:
1.24 schwarze 259: n = xcalloc(1, sizeof(*n));
260: TAILQ_INIT(&n->childq);
261: TAILQ_INIT(&n->attrq);
262: if ((n->parent = np) != NULL)
263: TAILQ_INSERT_TAIL(&np->childq, n, child);
1.25 schwarze 264: return n;
265: }
266:
267: struct pnode *
268: pnode_alloc_text(struct pnode *np, const char *text)
269: {
270: struct pnode *n;
271:
272: n = pnode_alloc(np);
273: n->node = NODE_TEXT;
274: n->b = xstrdup(text);
1.9 schwarze 275: return n;
1.1 schwarze 276: }
277:
278: /*
279: * Recursively free a node (NULL is ok).
280: */
281: static void
1.7 schwarze 282: pnode_free(struct pnode *n)
1.1 schwarze 283: {
1.7 schwarze 284: struct pnode *nc;
285: struct pattr *a;
1.1 schwarze 286:
1.7 schwarze 287: if (n == NULL)
1.1 schwarze 288: return;
289:
1.7 schwarze 290: while ((nc = TAILQ_FIRST(&n->childq)) != NULL) {
291: TAILQ_REMOVE(&n->childq, nc, child);
292: pnode_free(nc);
1.1 schwarze 293: }
1.7 schwarze 294: while ((a = TAILQ_FIRST(&n->attrq)) != NULL) {
295: TAILQ_REMOVE(&n->attrq, a, child);
296: free(a->rawval);
297: free(a);
1.1 schwarze 298: }
1.8 schwarze 299: free(n->b);
1.7 schwarze 300: free(n);
1.1 schwarze 301: }
302:
303: /*
304: * Unlink a node from its parent and pnode_free() it.
305: */
306: void
1.7 schwarze 307: pnode_unlink(struct pnode *n)
1.1 schwarze 308: {
1.7 schwarze 309: if (n == NULL)
1.1 schwarze 310: return;
1.7 schwarze 311: if (n->parent != NULL)
312: TAILQ_REMOVE(&n->parent->childq, n, child);
313: pnode_free(n);
1.1 schwarze 314: }
315:
316: /*
317: * Unlink all children of a node and pnode_free() them.
318: */
319: void
1.7 schwarze 320: pnode_unlinksub(struct pnode *n)
1.1 schwarze 321: {
1.7 schwarze 322: while (TAILQ_EMPTY(&n->childq) == 0)
323: pnode_unlink(TAILQ_FIRST(&n->childq));
1.1 schwarze 324: }
325:
326: /*
327: * Retrieve an enumeration attribute from a node.
328: * Return ATTRVAL__MAX if the node has no such attribute.
329: */
330: enum attrval
1.7 schwarze 331: pnode_getattr(struct pnode *n, enum attrkey key)
1.1 schwarze 332: {
1.7 schwarze 333: struct pattr *a;
1.1 schwarze 334:
1.7 schwarze 335: if (n == NULL)
1.1 schwarze 336: return ATTRVAL__MAX;
1.7 schwarze 337: TAILQ_FOREACH(a, &n->attrq, child)
338: if (a->key == key)
339: return a->val;
1.1 schwarze 340: return ATTRVAL__MAX;
341: }
342:
343: /*
344: * Retrieve an attribute string from a node.
345: * Return defval if the node has no such attribute.
346: */
347: const char *
1.7 schwarze 348: pnode_getattr_raw(struct pnode *n, enum attrkey key, const char *defval)
1.1 schwarze 349: {
1.7 schwarze 350: struct pattr *a;
1.1 schwarze 351:
1.7 schwarze 352: if (n == NULL)
1.1 schwarze 353: return defval;
1.7 schwarze 354: TAILQ_FOREACH(a, &n->attrq, child)
355: if (a->key == key)
356: return a->val != ATTRVAL__MAX ? attrvals[a->val] :
357: a->rawval != NULL ? a->rawval : defval;
1.1 schwarze 358: return defval;
359: }
360:
361: /*
362: * Recursively search and return the first instance of "node".
363: */
364: struct pnode *
1.7 schwarze 365: pnode_findfirst(struct pnode *n, enum nodeid node)
1.1 schwarze 366: {
1.7 schwarze 367: struct pnode *nc, *res;
1.1 schwarze 368:
1.12 schwarze 369: if (n == NULL)
370: return NULL;
1.7 schwarze 371: if (n->node == node)
372: return n;
373: TAILQ_FOREACH(nc, &n->childq, child)
374: if ((res = pnode_findfirst(nc, node)) != NULL)
1.1 schwarze 375: return res;
376: return NULL;
1.12 schwarze 377: }
378:
379: /*
380: * Like pnode_findfirst(), but also take the node out of the tree.
381: */
382: struct pnode *
383: pnode_takefirst(struct pnode *n, enum nodeid node)
384: {
385: struct pnode *nc;
386:
387: if ((nc = pnode_findfirst(n, node)) != NULL && nc->parent != NULL)
388: TAILQ_REMOVE(&nc->parent->childq, nc, child);
389: return nc;
1.1 schwarze 390: }
CVSweb