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