Annotation of docbook2mdoc/node.c, Revision 1.11
1.11 ! schwarze 1: /* $Id: node.c,v 1.10 2019/04/12 16:40:53 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 },
1.11 ! schwarze 147: { "(t)", CLASS_TEXT },
! 148: { "(e)", CLASS_TEXT }
1.10 schwarze 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:
1.11 ! schwarze 190: const char *
! 191: attrkey_name(enum attrkey key)
! 192: {
! 193: return attrkeys[key];
! 194: }
! 195:
1.1 schwarze 196: enum attrval
197: attrval_parse(const char *name)
198: {
199: enum attrval val;
200:
201: for (val = 0; val < ATTRVAL__MAX; val++)
202: if (strcmp(name, attrvals[val]) == 0)
203: break;
204: return val;
1.11 ! schwarze 205: }
! 206:
! 207: const char *
! 208: attr_getval(const struct pattr *a)
! 209: {
! 210: return a->val == ATTRVAL__MAX ? a->rawval : attrvals[a->val];
1.10 schwarze 211: }
212:
213: enum nodeid
214: pnode_parse(const char *name)
215: {
216: enum nodeid node;
217:
218: for (node = 0; node < NODE_UNKNOWN; node++)
219: if (strcmp(name, properties[node].name) == 0)
220: break;
221: return node;
222: }
223:
224: const char *
225: pnode_name(enum nodeid node)
226: {
227: assert(node < NODE_IGNORE);
228: return properties[node].name;
229: }
230:
231: enum nodeclass
232: pnode_class(enum nodeid node)
233: {
234: assert(node < NODE_IGNORE);
235: return properties[node].class;
1.9 schwarze 236: }
237:
238: struct pnode *
239: pnode_alloc(struct pnode *np)
240: {
241: struct pnode *n;
242:
243: if ((n = calloc(1, sizeof(*n))) != NULL) {
244: TAILQ_INIT(&n->childq);
245: TAILQ_INIT(&n->attrq);
246: if ((n->parent = np) != NULL)
247: TAILQ_INSERT_TAIL(&np->childq, n, child);
248: }
249: return n;
1.1 schwarze 250: }
251:
252: /*
253: * Recursively free a node (NULL is ok).
254: */
255: static void
1.7 schwarze 256: pnode_free(struct pnode *n)
1.1 schwarze 257: {
1.7 schwarze 258: struct pnode *nc;
259: struct pattr *a;
1.1 schwarze 260:
1.7 schwarze 261: if (n == NULL)
1.1 schwarze 262: return;
263:
1.7 schwarze 264: while ((nc = TAILQ_FIRST(&n->childq)) != NULL) {
265: TAILQ_REMOVE(&n->childq, nc, child);
266: pnode_free(nc);
1.1 schwarze 267: }
1.7 schwarze 268: while ((a = TAILQ_FIRST(&n->attrq)) != NULL) {
269: TAILQ_REMOVE(&n->attrq, a, child);
270: free(a->rawval);
271: free(a);
1.1 schwarze 272: }
1.8 schwarze 273: free(n->b);
1.7 schwarze 274: free(n);
1.1 schwarze 275: }
276:
277: /*
278: * Unlink a node from its parent and pnode_free() it.
279: */
280: void
1.7 schwarze 281: pnode_unlink(struct pnode *n)
1.1 schwarze 282: {
1.7 schwarze 283: if (n == NULL)
1.1 schwarze 284: return;
1.7 schwarze 285: if (n->parent != NULL)
286: TAILQ_REMOVE(&n->parent->childq, n, child);
287: pnode_free(n);
1.1 schwarze 288: }
289:
290: /*
291: * Unlink all children of a node and pnode_free() them.
292: */
293: void
1.7 schwarze 294: pnode_unlinksub(struct pnode *n)
1.1 schwarze 295: {
1.7 schwarze 296: while (TAILQ_EMPTY(&n->childq) == 0)
297: pnode_unlink(TAILQ_FIRST(&n->childq));
1.1 schwarze 298: }
299:
300: /*
301: * Retrieve an enumeration attribute from a node.
302: * Return ATTRVAL__MAX if the node has no such attribute.
303: */
304: enum attrval
1.7 schwarze 305: pnode_getattr(struct pnode *n, enum attrkey key)
1.1 schwarze 306: {
1.7 schwarze 307: struct pattr *a;
1.1 schwarze 308:
1.7 schwarze 309: if (n == NULL)
1.1 schwarze 310: return ATTRVAL__MAX;
1.7 schwarze 311: TAILQ_FOREACH(a, &n->attrq, child)
312: if (a->key == key)
313: return a->val;
1.1 schwarze 314: return ATTRVAL__MAX;
315: }
316:
317: /*
318: * Retrieve an attribute string from a node.
319: * Return defval if the node has no such attribute.
320: */
321: const char *
1.7 schwarze 322: pnode_getattr_raw(struct pnode *n, enum attrkey key, const char *defval)
1.1 schwarze 323: {
1.7 schwarze 324: struct pattr *a;
1.1 schwarze 325:
1.7 schwarze 326: if (n == NULL)
1.1 schwarze 327: return defval;
1.7 schwarze 328: TAILQ_FOREACH(a, &n->attrq, child)
329: if (a->key == key)
330: return a->val != ATTRVAL__MAX ? attrvals[a->val] :
331: a->rawval != NULL ? a->rawval : defval;
1.1 schwarze 332: return defval;
333: }
334:
335: /*
336: * Recursively search and return the first instance of "node".
337: */
338: struct pnode *
1.7 schwarze 339: pnode_findfirst(struct pnode *n, enum nodeid node)
1.1 schwarze 340: {
1.7 schwarze 341: struct pnode *nc, *res;
1.1 schwarze 342:
1.7 schwarze 343: if (n->node == node)
344: return n;
345: TAILQ_FOREACH(nc, &n->childq, child)
346: if ((res = pnode_findfirst(nc, node)) != NULL)
1.1 schwarze 347: return res;
348: return NULL;
349: }
CVSweb