17ec681f3Smrg/*
27ec681f3Smrg * Copyright (C) 2010-2011 Marcin Kościelnicki <koriakin@0x04.net>
37ec681f3Smrg * Copyright (C) 2010 Luca Barbieri <luca@luca-barbieri.com>
47ec681f3Smrg * Copyright (C) 2010 Francisco Jerez <currojerez@riseup.net>
57ec681f3Smrg * Copyright (C) 2010 Martin Peres <martin.peres@ensi-bourges.fr>
67ec681f3Smrg * Copyright (C) 2010 Marcin Slusarz <marcin.slusarz@gmail.com>
77ec681f3Smrg * All Rights Reserved.
87ec681f3Smrg *
97ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
107ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
117ec681f3Smrg * to deal in the Software without restriction, including without limitation
127ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
137ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
147ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
157ec681f3Smrg *
167ec681f3Smrg * The above copyright notice and this permission notice (including the next
177ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
187ec681f3Smrg * Software.
197ec681f3Smrg *
207ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
217ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
227ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
237ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
247ec681f3Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
257ec681f3Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
267ec681f3Smrg * OTHER DEALINGS IN THE SOFTWARE.
277ec681f3Smrg */
287ec681f3Smrg
297ec681f3Smrg/* workaround libxml2 silliness: */
307ec681f3Smrg#pragma GCC diagnostic ignored "-Wpointer-sign"
317ec681f3Smrg
327ec681f3Smrg#include <libxml/xmlversion.h>
337ec681f3Smrg#include <libxml/parser.h>
347ec681f3Smrg#include <libxml/xpath.h>
357ec681f3Smrg#include <libxml/xmlreader.h>
367ec681f3Smrg#include <stdint.h>
377ec681f3Smrg#include <string.h>
387ec681f3Smrg#include <limits.h>
397ec681f3Smrg#include <ctype.h>
407ec681f3Smrg#include <stdio.h>
417ec681f3Smrg#include "rnn.h"
427ec681f3Smrg#include "util.h"
437ec681f3Smrg
447ec681f3Smrg#include "util/u_debug.h"
457ec681f3Smrg
467ec681f3Smrgstatic char *catstr (char *a, char *b) {
477ec681f3Smrg	if (!a)
487ec681f3Smrg		return b;
497ec681f3Smrg	return aprintf("%s_%s", a, b);
507ec681f3Smrg}
517ec681f3Smrg
527ec681f3Smrgstatic int strdiff (const char *a, const char *b) {
537ec681f3Smrg	if (!a && !b)
547ec681f3Smrg		return 0;
557ec681f3Smrg	if (!a || !b)
567ec681f3Smrg		return 1;
577ec681f3Smrg	return strcmp (a, b);
587ec681f3Smrg}
597ec681f3Smrg
607ec681f3Smrgstatic void rnn_err(struct rnndb *db, const char *format, ...) _util_printf_format(2, 3);
617ec681f3Smrg
627ec681f3Smrgstatic void rnn_err(struct rnndb *db, const char *format, ...)
637ec681f3Smrg{
647ec681f3Smrg	va_list ap;
657ec681f3Smrg	va_start(ap, format);
667ec681f3Smrg	vfprintf(stderr, format, ap);
677ec681f3Smrg	va_end(ap);
687ec681f3Smrg	db->estatus = 1;
697ec681f3Smrg}
707ec681f3Smrg
717ec681f3Smrgvoid rnn_init(void) {
727ec681f3Smrg	LIBXML_TEST_VERSION
737ec681f3Smrg	xmlInitParser();
747ec681f3Smrg}
757ec681f3Smrg
767ec681f3Smrgstruct rnndb *rnn_newdb(void) {
777ec681f3Smrg	struct rnndb *db = calloc(sizeof *db, 1);
787ec681f3Smrg	return db;
797ec681f3Smrg}
807ec681f3Smrg
817ec681f3Smrgstatic char *getcontent (xmlNode *attr) {
827ec681f3Smrg	xmlNode *chain = attr->children;
837ec681f3Smrg	size_t size = 0;
847ec681f3Smrg	char *content, *p;
857ec681f3Smrg	while (chain) {
867ec681f3Smrg		if (chain->type == XML_TEXT_NODE)
877ec681f3Smrg			size += strlen(chain->content);
887ec681f3Smrg		chain = chain->next;
897ec681f3Smrg	}
907ec681f3Smrg	p = content = malloc(size + 1);
917ec681f3Smrg	chain = attr->children;
927ec681f3Smrg	while (chain) {
937ec681f3Smrg		if (chain->type == XML_TEXT_NODE) {
947ec681f3Smrg			char* sp = chain->content;
957ec681f3Smrg			if(p == content) {
967ec681f3Smrg				while(isspace(*sp))
977ec681f3Smrg					++sp;
987ec681f3Smrg			}
997ec681f3Smrg			size_t len = strlen(sp);
1007ec681f3Smrg			memcpy(p, sp, len);
1017ec681f3Smrg			p += len;
1027ec681f3Smrg		}
1037ec681f3Smrg		chain = chain->next;
1047ec681f3Smrg	}
1057ec681f3Smrg	while(p != content && isspace(p[-1]))
1067ec681f3Smrg		--p;
1077ec681f3Smrg	*p = 0;
1087ec681f3Smrg	return content;
1097ec681f3Smrg}
1107ec681f3Smrg
1117ec681f3Smrgstatic char *getattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
1127ec681f3Smrg	xmlNode *chain = attr->children;
1137ec681f3Smrg	while (chain) {
1147ec681f3Smrg		if (chain->type != XML_TEXT_NODE) {
1157ec681f3Smrg			rnn_err(db, "%s:%d: unknown attribute child \"%s\" in attribute \"%s\"\n", file, line, chain->name, attr->name);
1167ec681f3Smrg		} else {
1177ec681f3Smrg			return chain->content;
1187ec681f3Smrg		}
1197ec681f3Smrg		chain = chain->next;
1207ec681f3Smrg	}
1217ec681f3Smrg	return "";
1227ec681f3Smrg}
1237ec681f3Smrg
1247ec681f3Smrgstatic int getboolattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
1257ec681f3Smrg	char *c = getattrib(db, file, line, attr);
1267ec681f3Smrg	if (!strcmp(c, "yes") || !strcmp(c, "1") || !strcmp(c, "true"))
1277ec681f3Smrg		return 1;
1287ec681f3Smrg	if (!strcmp(c, "no") || !strcmp(c, "0") || !strcmp(c, "false"))
1297ec681f3Smrg		return 0;
1307ec681f3Smrg	rnn_err(db, "%s:%d: invalid boolean value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name);
1317ec681f3Smrg	return 0;
1327ec681f3Smrg}
1337ec681f3Smrg
1347ec681f3Smrgstatic uint64_t getnum(struct rnndb *db, char *file, int line, xmlAttr *attr, char *c)
1357ec681f3Smrg{
1367ec681f3Smrg	char *cc;
1377ec681f3Smrg	uint64_t res;
1387ec681f3Smrg	if (strchr(c, 'x') || strchr(c, 'X'))
1397ec681f3Smrg		res = strtoull(c, &cc, 16);
1407ec681f3Smrg	else
1417ec681f3Smrg		res = strtoull(c, &cc, 10);
1427ec681f3Smrg	if (*cc)  {
1437ec681f3Smrg		rnn_err(db, "%s:%d: invalid numeric value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name);
1447ec681f3Smrg	}
1457ec681f3Smrg	return res;
1467ec681f3Smrg}
1477ec681f3Smrg
1487ec681f3Smrgstatic uint64_t getnumattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
1497ec681f3Smrg	char *c = getattrib(db, file, line, attr);
1507ec681f3Smrg	return getnum(db, file, line, attr, c);
1517ec681f3Smrg}
1527ec681f3Smrg
1537ec681f3Smrgstatic int trytop (struct rnndb *db, char *file, xmlNode *node);
1547ec681f3Smrg
1557ec681f3Smrgstatic int trydoc (struct rnndb *db, char *file, xmlNode *node) {
1567ec681f3Smrg	if (!strcmp(node->name, "brief")) {
1577ec681f3Smrg		return 1;
1587ec681f3Smrg	} else if (!strcmp(node->name, "doc")) {
1597ec681f3Smrg		return 1;
1607ec681f3Smrg	}
1617ec681f3Smrg	return 0;
1627ec681f3Smrg}
1637ec681f3Smrg
1647ec681f3Smrgstatic struct rnnvalue *parsevalue(struct rnndb *db, char *file, xmlNode *node);
1657ec681f3Smrgstatic struct rnnbitfield *parsebitfield(struct rnndb *db, char *file, xmlNode *node);
1667ec681f3Smrg
1677ec681f3Smrgstatic int trytypetag (struct rnndb *db, char *file, xmlNode *node, struct rnntypeinfo *ti) {
1687ec681f3Smrg	if (!strcmp(node->name, "value")) {
1697ec681f3Smrg		struct rnnvalue *val = parsevalue(db, file, node);
1707ec681f3Smrg		if (val)
1717ec681f3Smrg			ADDARRAY(ti->vals, val);
1727ec681f3Smrg		return 1;
1737ec681f3Smrg	} else if (!strcmp(node->name, "bitfield")) {
1747ec681f3Smrg		struct rnnbitfield *bf = parsebitfield(db, file, node);
1757ec681f3Smrg		if (bf)
1767ec681f3Smrg			ADDARRAY(ti->bitfields, bf);
1777ec681f3Smrg		return 1;
1787ec681f3Smrg	}
1797ec681f3Smrg	return 0;
1807ec681f3Smrg}
1817ec681f3Smrgstatic int trytypeattr (struct rnndb *db, char *file, xmlNode *node, xmlAttr *attr, struct rnntypeinfo *ti) {
1827ec681f3Smrg	if (!strcmp(attr->name, "shr")) {
1837ec681f3Smrg		ti->shr = getnumattrib(db, file, node->line, attr);
1847ec681f3Smrg		return 1;
1857ec681f3Smrg	} else if (!strcmp(attr->name, "min")) {
1867ec681f3Smrg		ti->min = getnumattrib(db, file, node->line, attr);
1877ec681f3Smrg		ti->minvalid = 1;
1887ec681f3Smrg		return 1;
1897ec681f3Smrg	} else if (!strcmp(attr->name, "max")) {
1907ec681f3Smrg		ti->max = getnumattrib(db, file, node->line, attr);
1917ec681f3Smrg		ti->maxvalid = 1;
1927ec681f3Smrg		return 1;
1937ec681f3Smrg	} else if (!strcmp(attr->name, "align")) {
1947ec681f3Smrg		ti->align = getnumattrib(db, file, node->line, attr);
1957ec681f3Smrg		ti->alignvalid = 1;
1967ec681f3Smrg		return 1;
1977ec681f3Smrg	} else if (!strcmp(attr->name, "type")) {
1987ec681f3Smrg		ti->name = strdup(getattrib(db, file, node->line, attr));;
1997ec681f3Smrg		return 1;
2007ec681f3Smrg	} else if (!strcmp(attr->name, "radix")) {
2017ec681f3Smrg		ti->radix = getnumattrib(db, file, node->line, attr);
2027ec681f3Smrg		ti->radixvalid = 1;
2037ec681f3Smrg		return 1;
2047ec681f3Smrg	} else if (!strcmp(attr->name, "pos")) {
2057ec681f3Smrg		ti->high = ti->low = getnumattrib(db, file, node->line, attr);
2067ec681f3Smrg		return 1;
2077ec681f3Smrg	} else if (!strcmp(attr->name, "low")) {
2087ec681f3Smrg		ti->low = getnumattrib(db, file, node->line, attr);
2097ec681f3Smrg		return 1;
2107ec681f3Smrg	} else if (!strcmp(attr->name, "high")) {
2117ec681f3Smrg		ti->high = getnumattrib(db, file, node->line, attr);
2127ec681f3Smrg		return 1;
2137ec681f3Smrg	} else if (!strcmp(attr->name, "addvariant")) {
2147ec681f3Smrg		ti->addvariant = getboolattrib(db, file, node->line, attr);
2157ec681f3Smrg		return 1;
2167ec681f3Smrg	}
2177ec681f3Smrg	return 0;
2187ec681f3Smrg}
2197ec681f3Smrg
2207ec681f3Smrgstatic struct rnnvalue *parsevalue(struct rnndb *db, char *file, xmlNode *node) {
2217ec681f3Smrg	struct rnnvalue *val = calloc(sizeof *val, 1);
2227ec681f3Smrg	val->file = file;
2237ec681f3Smrg	xmlAttr *attr = node->properties;
2247ec681f3Smrg	while (attr) {
2257ec681f3Smrg		if (!strcmp(attr->name, "name")) {
2267ec681f3Smrg			val->name = strdup(getattrib(db, file, node->line, attr));
2277ec681f3Smrg		} else if (!strcmp(attr->name, "value")) {
2287ec681f3Smrg			val->value = getnumattrib(db, file, node->line, attr);
2297ec681f3Smrg			val->valvalid = 1;
2307ec681f3Smrg		} else if (!strcmp(attr->name, "varset")) {
2317ec681f3Smrg			val->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
2327ec681f3Smrg		} else if (!strcmp(attr->name, "variants")) {
2337ec681f3Smrg			val->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
2347ec681f3Smrg		} else {
2357ec681f3Smrg			rnn_err(db, "%s:%d: wrong attribute \"%s\" for value\n", file, node->line, attr->name);
2367ec681f3Smrg		}
2377ec681f3Smrg		attr = attr->next;
2387ec681f3Smrg	}
2397ec681f3Smrg	xmlNode *chain = node->children;
2407ec681f3Smrg	while (chain) {
2417ec681f3Smrg		if (chain->type != XML_ELEMENT_NODE) {
2427ec681f3Smrg		} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
2437ec681f3Smrg			rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
2447ec681f3Smrg		}
2457ec681f3Smrg		chain = chain->next;
2467ec681f3Smrg	}
2477ec681f3Smrg	if (!val->name) {
2487ec681f3Smrg		rnn_err(db, "%s:%d: nameless value\n", file, node->line);
2497ec681f3Smrg		return 0;
2507ec681f3Smrg	} else {
2517ec681f3Smrg		return val;
2527ec681f3Smrg	}
2537ec681f3Smrg}
2547ec681f3Smrg
2557ec681f3Smrgstatic void parsespectype(struct rnndb *db, char *file, xmlNode *node) {
2567ec681f3Smrg	struct rnnspectype *res = calloc (sizeof *res, 1);
2577ec681f3Smrg	res->file = file;
2587ec681f3Smrg	xmlAttr *attr = node->properties;
2597ec681f3Smrg	int i;
2607ec681f3Smrg	while (attr) {
2617ec681f3Smrg		if (!strcmp(attr->name, "name")) {
2627ec681f3Smrg			res->name = strdup(getattrib(db, file, node->line, attr));
2637ec681f3Smrg		} else if (!trytypeattr(db, file, node, attr, &res->typeinfo)) {
2647ec681f3Smrg			rnn_err(db, "%s:%d: wrong attribute \"%s\" for spectype\n", file, node->line, attr->name);
2657ec681f3Smrg		}
2667ec681f3Smrg		attr = attr->next;
2677ec681f3Smrg	}
2687ec681f3Smrg	if (!res->name) {
2697ec681f3Smrg		rnn_err(db, "%s:%d: nameless spectype\n", file, node->line);
2707ec681f3Smrg		return;
2717ec681f3Smrg	}
2727ec681f3Smrg	for (i = 0; i < db->spectypesnum; i++)
2737ec681f3Smrg		if (!strcmp(db->spectypes[i]->name, res->name)) {
2747ec681f3Smrg			rnn_err(db, "%s:%d: duplicated spectype name %s\n", file, node->line, res->name);
2757ec681f3Smrg			return;
2767ec681f3Smrg		}
2777ec681f3Smrg	ADDARRAY(db->spectypes, res);
2787ec681f3Smrg	xmlNode *chain = node->children;
2797ec681f3Smrg	while (chain) {
2807ec681f3Smrg		if (chain->type != XML_ELEMENT_NODE) {
2817ec681f3Smrg		} else if (!trytypetag(db, file, chain, &res->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) {
2827ec681f3Smrg			rnn_err(db, "%s:%d: wrong tag in spectype: <%s>\n", file, chain->line, chain->name);
2837ec681f3Smrg		}
2847ec681f3Smrg		chain = chain->next;
2857ec681f3Smrg	}
2867ec681f3Smrg}
2877ec681f3Smrg
2887ec681f3Smrgstatic void parseenum(struct rnndb *db, char *file, xmlNode *node) {
2897ec681f3Smrg	xmlAttr *attr = node->properties;
2907ec681f3Smrg	char *name = 0;
2917ec681f3Smrg	int isinline = 0;
2927ec681f3Smrg	int bare = 0;
2937ec681f3Smrg	char *prefixstr = 0;
2947ec681f3Smrg	char *varsetstr = 0;
2957ec681f3Smrg	char *variantsstr = 0;
2967ec681f3Smrg	int i;
2977ec681f3Smrg	while (attr) {
2987ec681f3Smrg		if (!strcmp(attr->name, "name")) {
2997ec681f3Smrg			name = getattrib(db, file, node->line, attr);
3007ec681f3Smrg		} else if (!strcmp(attr->name, "bare")) {
3017ec681f3Smrg			bare = getboolattrib(db, file, node->line, attr);
3027ec681f3Smrg		} else if (!strcmp(attr->name, "inline")) {
3037ec681f3Smrg			isinline = getboolattrib(db, file, node->line, attr);
3047ec681f3Smrg		} else if (!strcmp(attr->name, "prefix")) {
3057ec681f3Smrg			prefixstr = strdup(getattrib(db, file, node->line, attr));
3067ec681f3Smrg		} else if (!strcmp(attr->name, "varset")) {
3077ec681f3Smrg			varsetstr = strdup(getattrib(db, file, node->line, attr));
3087ec681f3Smrg		} else if (!strcmp(attr->name, "variants")) {
3097ec681f3Smrg			variantsstr = strdup(getattrib(db, file, node->line, attr));
3107ec681f3Smrg		} else {
3117ec681f3Smrg			rnn_err(db, "%s:%d: wrong attribute \"%s\" for enum\n", file, node->line, attr->name);
3127ec681f3Smrg		}
3137ec681f3Smrg		attr = attr->next;
3147ec681f3Smrg	}
3157ec681f3Smrg	if (!name) {
3167ec681f3Smrg		rnn_err(db, "%s:%d: nameless enum\n", file, node->line);
3177ec681f3Smrg		return;
3187ec681f3Smrg	}
3197ec681f3Smrg	struct rnnenum *cur = 0;
3207ec681f3Smrg	for (i = 0; i < db->enumsnum; i++)
3217ec681f3Smrg		if (!strcmp(db->enums[i]->name, name)) {
3227ec681f3Smrg			cur = db->enums[i];
3237ec681f3Smrg			break;
3247ec681f3Smrg		}
3257ec681f3Smrg	if (cur) {
3267ec681f3Smrg		if (strdiff(cur->varinfo.prefixstr, prefixstr) ||
3277ec681f3Smrg				strdiff(cur->varinfo.varsetstr, varsetstr) ||
3287ec681f3Smrg				strdiff(cur->varinfo.variantsstr, variantsstr) ||
3297ec681f3Smrg				cur->isinline != isinline || cur->bare != bare) {
3307ec681f3Smrg			rnn_err(db, "%s:%d: merge fail for enum %s\n", file, node->line, node->name);
3317ec681f3Smrg		}
3327ec681f3Smrg	} else {
3337ec681f3Smrg		cur = calloc(sizeof *cur, 1);
3347ec681f3Smrg		cur->name = strdup(name);
3357ec681f3Smrg		cur->isinline = isinline;
3367ec681f3Smrg		cur->bare = bare;
3377ec681f3Smrg		cur->varinfo.prefixstr = prefixstr;
3387ec681f3Smrg		cur->varinfo.varsetstr = varsetstr;
3397ec681f3Smrg		cur->varinfo.variantsstr = variantsstr;
3407ec681f3Smrg		cur->file = file;
3417ec681f3Smrg		ADDARRAY(db->enums, cur);
3427ec681f3Smrg	}
3437ec681f3Smrg	xmlNode *chain = node->children;
3447ec681f3Smrg	while (chain) {
3457ec681f3Smrg		if (chain->type != XML_ELEMENT_NODE) {
3467ec681f3Smrg		} else if (!strcmp(chain->name, "value")) {
3477ec681f3Smrg			struct rnnvalue *val = parsevalue(db, file, chain);
3487ec681f3Smrg			if (val)
3497ec681f3Smrg				ADDARRAY(cur->vals, val);
3507ec681f3Smrg		} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
3517ec681f3Smrg			rnn_err(db, "%s:%d: wrong tag in enum: <%s>\n", file, chain->line, chain->name);
3527ec681f3Smrg		}
3537ec681f3Smrg		chain = chain->next;
3547ec681f3Smrg	}
3557ec681f3Smrg}
3567ec681f3Smrg
3577ec681f3Smrgstatic struct rnnbitfield *parsebitfield(struct rnndb *db, char *file, xmlNode *node) {
3587ec681f3Smrg	struct rnnbitfield *bf = calloc(sizeof *bf, 1);
3597ec681f3Smrg	bf->file = file;
3607ec681f3Smrg	xmlAttr *attr = node->properties;
3617ec681f3Smrg	bf->typeinfo.low = bf->typeinfo.high = -1;
3627ec681f3Smrg	while (attr) {
3637ec681f3Smrg		if (!strcmp(attr->name, "name")) {
3647ec681f3Smrg			bf->name = strdup(getattrib(db, file, node->line, attr));
3657ec681f3Smrg		} else if (!strcmp(attr->name, "varset")) {
3667ec681f3Smrg			bf->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
3677ec681f3Smrg		} else if (!strcmp(attr->name, "variants")) {
3687ec681f3Smrg			bf->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
3697ec681f3Smrg		} else if (!trytypeattr(db, file, node, attr, &bf->typeinfo)) {
3707ec681f3Smrg			rnn_err(db, "%s:%d: wrong attribute \"%s\" for bitfield\n", file, node->line, attr->name);
3717ec681f3Smrg		}
3727ec681f3Smrg		attr = attr->next;
3737ec681f3Smrg	}
3747ec681f3Smrg	xmlNode *chain = node->children;
3757ec681f3Smrg	while (chain) {
3767ec681f3Smrg		if (chain->type != XML_ELEMENT_NODE) {
3777ec681f3Smrg		} else if (!trytypetag(db, file, chain, &bf->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) {
3787ec681f3Smrg			rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
3797ec681f3Smrg		}
3807ec681f3Smrg		chain = chain->next;
3817ec681f3Smrg	}
3827ec681f3Smrg	if (!bf->name) {
3837ec681f3Smrg		rnn_err(db, "%s:%d: nameless bitfield\n", file, node->line);
3847ec681f3Smrg		return 0;
3857ec681f3Smrg	} else if (bf->typeinfo.low < 0|| bf->typeinfo.high < 0 || bf->typeinfo.high < bf->typeinfo.low) {
3867ec681f3Smrg		rnn_err(db, "%s:%d: bitfield has wrong placement\n", file, node->line);
3877ec681f3Smrg		return 0;
3887ec681f3Smrg	} else {
3897ec681f3Smrg		return bf;
3907ec681f3Smrg	}
3917ec681f3Smrg}
3927ec681f3Smrg
3937ec681f3Smrgstatic void parsebitset(struct rnndb *db, char *file, xmlNode *node) {
3947ec681f3Smrg	xmlAttr *attr = node->properties;
3957ec681f3Smrg	char *name = 0;
3967ec681f3Smrg	int isinline = 0;
3977ec681f3Smrg	int bare = 0;
3987ec681f3Smrg	char *prefixstr = 0;
3997ec681f3Smrg	char *varsetstr = 0;
4007ec681f3Smrg	char *variantsstr = 0;
4017ec681f3Smrg	int i;
4027ec681f3Smrg	while (attr) {
4037ec681f3Smrg		if (!strcmp(attr->name, "name")) {
4047ec681f3Smrg			name = getattrib(db, file, node->line, attr);
4057ec681f3Smrg		} else if (!strcmp(attr->name, "bare")) {
4067ec681f3Smrg			bare = getboolattrib(db, file, node->line, attr);
4077ec681f3Smrg		} else if (!strcmp(attr->name, "inline")) {
4087ec681f3Smrg			isinline = getboolattrib(db, file, node->line, attr);
4097ec681f3Smrg		} else if (!strcmp(attr->name, "prefix")) {
4107ec681f3Smrg			prefixstr = strdup(getattrib(db, file, node->line, attr));
4117ec681f3Smrg		} else if (!strcmp(attr->name, "varset")) {
4127ec681f3Smrg			varsetstr = strdup(getattrib(db, file, node->line, attr));
4137ec681f3Smrg		} else if (!strcmp(attr->name, "variants")) {
4147ec681f3Smrg			variantsstr = strdup(getattrib(db, file, node->line, attr));
4157ec681f3Smrg		} else {
4167ec681f3Smrg			rnn_err(db, "%s:%d: wrong attribute \"%s\" for bitset\n", file, node->line, attr->name);
4177ec681f3Smrg		}
4187ec681f3Smrg		attr = attr->next;
4197ec681f3Smrg	}
4207ec681f3Smrg	if (!name) {
4217ec681f3Smrg		rnn_err(db, "%s:%d: nameless bitset\n", file, node->line);
4227ec681f3Smrg		return;
4237ec681f3Smrg	}
4247ec681f3Smrg	struct rnnbitset *cur = 0;
4257ec681f3Smrg	for (i = 0; i < db->bitsetsnum; i++)
4267ec681f3Smrg		if (!strcmp(db->bitsets[i]->name, name)) {
4277ec681f3Smrg			cur = db->bitsets[i];
4287ec681f3Smrg			break;
4297ec681f3Smrg		}
4307ec681f3Smrg	if (cur) {
4317ec681f3Smrg		if (strdiff(cur->varinfo.prefixstr, prefixstr) ||
4327ec681f3Smrg				strdiff(cur->varinfo.varsetstr, varsetstr) ||
4337ec681f3Smrg				strdiff(cur->varinfo.variantsstr, variantsstr) ||
4347ec681f3Smrg				cur->isinline != isinline || cur->bare != bare) {
4357ec681f3Smrg			rnn_err(db, "%s:%d: merge fail for bitset %s\n", file, node->line, node->name);
4367ec681f3Smrg		}
4377ec681f3Smrg	} else {
4387ec681f3Smrg		cur = calloc(sizeof *cur, 1);
4397ec681f3Smrg		cur->name = strdup(name);
4407ec681f3Smrg		cur->isinline = isinline;
4417ec681f3Smrg		cur->bare = bare;
4427ec681f3Smrg		cur->varinfo.prefixstr = prefixstr;
4437ec681f3Smrg		cur->varinfo.varsetstr = varsetstr;
4447ec681f3Smrg		cur->varinfo.variantsstr = variantsstr;
4457ec681f3Smrg		cur->file = file;
4467ec681f3Smrg		ADDARRAY(db->bitsets, cur);
4477ec681f3Smrg	}
4487ec681f3Smrg	xmlNode *chain = node->children;
4497ec681f3Smrg	while (chain) {
4507ec681f3Smrg		if (chain->type != XML_ELEMENT_NODE) {
4517ec681f3Smrg		} else if (!strcmp(chain->name, "bitfield")) {
4527ec681f3Smrg			struct rnnbitfield *bf = parsebitfield(db, file, chain);
4537ec681f3Smrg			if (bf)
4547ec681f3Smrg				ADDARRAY(cur->bitfields, bf);
4557ec681f3Smrg		} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
4567ec681f3Smrg			rnn_err(db, "%s:%d: wrong tag in bitset: <%s>\n", file, chain->line, chain->name);
4577ec681f3Smrg		}
4587ec681f3Smrg		chain = chain->next;
4597ec681f3Smrg	}
4607ec681f3Smrg}
4617ec681f3Smrg
4627ec681f3Smrgstatic struct rnndelem *trydelem(struct rnndb *db, char *file, xmlNode *node) {
4637ec681f3Smrg	if (!strcmp(node->name, "use-group")) {
4647ec681f3Smrg		struct rnndelem *res = calloc(sizeof *res, 1);
4657ec681f3Smrg		res->file = file;
4667ec681f3Smrg		res->type = RNN_ETYPE_USE_GROUP;
4677ec681f3Smrg		xmlAttr *attr = node->properties;
4687ec681f3Smrg		while (attr) {
4697ec681f3Smrg			if (!strcmp(attr->name, "ref")) {
4707ec681f3Smrg				res->name = strdup(getattrib(db, file, node->line, attr));
4717ec681f3Smrg			} else {
4727ec681f3Smrg				rnn_err(db, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name);
4737ec681f3Smrg			}
4747ec681f3Smrg			attr = attr->next;
4757ec681f3Smrg		}
4767ec681f3Smrg		if (!res->name) {
4777ec681f3Smrg			rnn_err(db, "%s:%d: nameless use-group\n", file, node->line);
4787ec681f3Smrg			return 0;
4797ec681f3Smrg		}
4807ec681f3Smrg		return res;
4817ec681f3Smrg	} else if (!strcmp(node->name, "stripe") || !strcmp(node->name, "array")) {
4827ec681f3Smrg		struct rnndelem *res = calloc(sizeof *res, 1);
4837ec681f3Smrg		if (!strcmp(node->name, "array"))
4847ec681f3Smrg			res->name = "";
4857ec681f3Smrg		res->type = (strcmp(node->name, "stripe")?RNN_ETYPE_ARRAY:RNN_ETYPE_STRIPE);
4867ec681f3Smrg		res->length = 1;
4877ec681f3Smrg		res->file = file;
4887ec681f3Smrg		xmlAttr *attr = node->properties;
4897ec681f3Smrg		while (attr) {
4907ec681f3Smrg			if (!strcmp(attr->name, "name")) {
4917ec681f3Smrg				res->name = strdup(getattrib(db, file, node->line, attr));
4927ec681f3Smrg			} else if (!strcmp(attr->name, "offset")) {
4937ec681f3Smrg				res->offset = getnumattrib(db, file, node->line, attr);
4947ec681f3Smrg			} else if (!strcmp(attr->name, "offsets")) {
4957ec681f3Smrg				char *str = strdup(getattrib(db, file, node->line, attr));
4967ec681f3Smrg				char *tok, *save, *tmp = str;
4977ec681f3Smrg				while ((tok = strtok_r(str, ",", &save))) {
4987ec681f3Smrg					uint64_t offset = getnum(db, file, node->line, attr, tok);
4997ec681f3Smrg					ADDARRAY(res->offsets, offset);
5007ec681f3Smrg					str = NULL;
5017ec681f3Smrg				}
5027ec681f3Smrg				if (str)
5037ec681f3Smrg					fprintf(stderr, "%s:%d: invalid offsets: %s\n", file, node->line, str);
5047ec681f3Smrg				free(tmp);
5057ec681f3Smrg			} else if (!strcmp(attr->name, "doffset")) {
5067ec681f3Smrg				/* dynamic runtime determined offset: */
5077ec681f3Smrg				res->doffset = strdup(getattrib(db, file, node->line, attr));
5087ec681f3Smrg			} else if (!strcmp(attr->name, "doffsets")) {
5097ec681f3Smrg				/* dynamic runtime determined offsets: */
5107ec681f3Smrg				char *str = strdup(getattrib(db, file, node->line, attr));
5117ec681f3Smrg				char *tok, *save, *tmp = str;
5127ec681f3Smrg				while ((tok = strtok_r(str, ",", &save))) {
5137ec681f3Smrg					char *doffset = strdup(tok);
5147ec681f3Smrg					ADDARRAY(res->doffsets, doffset);
5157ec681f3Smrg					str = NULL;
5167ec681f3Smrg				}
5177ec681f3Smrg				if (str)
5187ec681f3Smrg					fprintf(stderr, "%s:%d: invalid offsets: %s\n", file, node->line, str);
5197ec681f3Smrg				free(tmp);
5207ec681f3Smrg			} else if (!strcmp(attr->name, "length")) {
5217ec681f3Smrg				res->length = getnumattrib(db, file, node->line, attr);
5227ec681f3Smrg			} else if (!strcmp(attr->name, "stride")) {
5237ec681f3Smrg				res->stride = getnumattrib(db, file, node->line, attr);
5247ec681f3Smrg			} else if (!strcmp(attr->name, "prefix")) {
5257ec681f3Smrg				res->varinfo.prefixstr = strdup(getattrib(db, file, node->line, attr));
5267ec681f3Smrg			} else if (!strcmp(attr->name, "varset")) {
5277ec681f3Smrg				res->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
5287ec681f3Smrg			} else if (!strcmp(attr->name, "variants")) {
5297ec681f3Smrg				res->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
5307ec681f3Smrg			} else if (!strcmp(attr->name, "index")) {
5317ec681f3Smrg				const char *enumname = getattrib(db, file, node->line, attr);
5327ec681f3Smrg				res->index = rnn_findenum(db, enumname);
5337ec681f3Smrg				if (!res->index) {
5347ec681f3Smrg					rnn_err(db, "%s:%d: invalid enum name \"%s\"\n", file, node->line, enumname);
5357ec681f3Smrg				}
5367ec681f3Smrg			} else {
5377ec681f3Smrg				rnn_err(db, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name);
5387ec681f3Smrg			}
5397ec681f3Smrg			attr = attr->next;
5407ec681f3Smrg		}
5417ec681f3Smrg		xmlNode *chain = node->children;
5427ec681f3Smrg		while (chain) {
5437ec681f3Smrg			struct rnndelem *delem;
5447ec681f3Smrg			if (chain->type != XML_ELEMENT_NODE) {
5457ec681f3Smrg			} else if ((delem = trydelem(db, file, chain))) {
5467ec681f3Smrg				ADDARRAY(res->subelems, delem);
5477ec681f3Smrg			} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
5487ec681f3Smrg				rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
5497ec681f3Smrg			}
5507ec681f3Smrg			chain = chain->next;
5517ec681f3Smrg		}
5527ec681f3Smrg
5537ec681f3Smrg		/* Sanity checking */
5547ec681f3Smrg		if (res->type == RNN_ETYPE_ARRAY && res->stride == 0) {
5557ec681f3Smrg			fprintf(stderr, "%s: Array %s's stride is undefined. Aborting.\n", file, res->name);
5567ec681f3Smrg			exit(-1);
5577ec681f3Smrg		}
5587ec681f3Smrg		return res;
5597ec681f3Smrg
5607ec681f3Smrg	}
5617ec681f3Smrg	int width;
5627ec681f3Smrg	if (!strcmp(node->name, "reg8"))
5637ec681f3Smrg		width = 8;
5647ec681f3Smrg	else if (!strcmp(node->name, "reg16"))
5657ec681f3Smrg		width = 16;
5667ec681f3Smrg	else if (!strcmp(node->name, "reg32"))
5677ec681f3Smrg		width = 32;
5687ec681f3Smrg	else if (!strcmp(node->name, "reg64"))
5697ec681f3Smrg		width = 64;
5707ec681f3Smrg	else
5717ec681f3Smrg		return 0;
5727ec681f3Smrg	struct rnndelem *res = calloc(sizeof *res, 1);
5737ec681f3Smrg	res->file = file;
5747ec681f3Smrg	res->type = RNN_ETYPE_REG;
5757ec681f3Smrg	res->width = width;
5767ec681f3Smrg	res->length = 1;
5777ec681f3Smrg	res->access = RNN_ACCESS_RW;
5787ec681f3Smrg	xmlAttr *attr = node->properties;
5797ec681f3Smrg	res->typeinfo.low = 0;
5807ec681f3Smrg	res->typeinfo.high = width - 1;
5817ec681f3Smrg	while (attr) {
5827ec681f3Smrg		if (!strcmp(attr->name, "name")) {
5837ec681f3Smrg			res->name = strdup(getattrib(db, file, node->line, attr));
5847ec681f3Smrg		} else if (!strcmp(attr->name, "offset")) {
5857ec681f3Smrg			res->offset = getnumattrib(db, file, node->line, attr);
5867ec681f3Smrg		} else if (!strcmp(attr->name, "length")) {
5877ec681f3Smrg			res->length = getnumattrib(db, file, node->line, attr);
5887ec681f3Smrg		} else if (!strcmp(attr->name, "stride")) {
5897ec681f3Smrg			res->stride = getnumattrib(db, file, node->line, attr);
5907ec681f3Smrg		} else if (!strcmp(attr->name, "varset")) {
5917ec681f3Smrg			res->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
5927ec681f3Smrg		} else if (!strcmp(attr->name, "variants")) {
5937ec681f3Smrg			res->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
5947ec681f3Smrg		} else if (!strcmp(attr->name, "access")) {
5957ec681f3Smrg			char *str = getattrib(db, file, node->line, attr);
5967ec681f3Smrg			if (!strcmp(str, "r"))
5977ec681f3Smrg				res->access = RNN_ACCESS_R;
5987ec681f3Smrg			else if (!strcmp(str, "w"))
5997ec681f3Smrg				res->access = RNN_ACCESS_W;
6007ec681f3Smrg			else if (!strcmp(str, "rw"))
6017ec681f3Smrg				res->access = RNN_ACCESS_RW;
6027ec681f3Smrg			else
6037ec681f3Smrg				fprintf (stderr, "%s:%d: wrong access type \"%s\" for register\n", file, node->line, str);
6047ec681f3Smrg		} else if (!trytypeattr(db, file, node, attr, &res->typeinfo)) {
6057ec681f3Smrg			rnn_err(db, "%s:%d: wrong attribute \"%s\" for register\n", file, node->line, attr->name);
6067ec681f3Smrg		}
6077ec681f3Smrg		attr = attr->next;
6087ec681f3Smrg	}
6097ec681f3Smrg	xmlNode *chain = node->children;
6107ec681f3Smrg	while (chain) {
6117ec681f3Smrg		if (chain->type != XML_ELEMENT_NODE) {
6127ec681f3Smrg		} else if (!trytypetag(db, file, chain, &res->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) {
6137ec681f3Smrg			rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
6147ec681f3Smrg		}
6157ec681f3Smrg		chain = chain->next;
6167ec681f3Smrg	}
6177ec681f3Smrg	if (!res->name) {
6187ec681f3Smrg		rnn_err(db, "%s:%d: nameless register\n", file, node->line);
6197ec681f3Smrg		return 0;
6207ec681f3Smrg	} else {
6217ec681f3Smrg	}
6227ec681f3Smrg	return res;
6237ec681f3Smrg}
6247ec681f3Smrg
6257ec681f3Smrgstatic void parsegroup(struct rnndb *db, char *file, xmlNode *node) {
6267ec681f3Smrg	xmlAttr *attr = node->properties;
6277ec681f3Smrg	char *name = 0;
6287ec681f3Smrg	int i;
6297ec681f3Smrg	while (attr) {
6307ec681f3Smrg		if (!strcmp(attr->name, "name")) {
6317ec681f3Smrg			name = getattrib(db, file, node->line, attr);
6327ec681f3Smrg		} else {
6337ec681f3Smrg			rnn_err(db, "%s:%d: wrong attribute \"%s\" for group\n", file, node->line, attr->name);
6347ec681f3Smrg		}
6357ec681f3Smrg		attr = attr->next;
6367ec681f3Smrg	}
6377ec681f3Smrg	if (!name) {
6387ec681f3Smrg		rnn_err(db, "%s:%d: nameless group\n", file, node->line);
6397ec681f3Smrg		return;
6407ec681f3Smrg	}
6417ec681f3Smrg	struct rnngroup *cur = 0;
6427ec681f3Smrg	for (i = 0; i < db->groupsnum; i++)
6437ec681f3Smrg		if (!strcmp(db->groups[i]->name, name)) {
6447ec681f3Smrg			cur = db->groups[i];
6457ec681f3Smrg			break;
6467ec681f3Smrg		}
6477ec681f3Smrg	if (!cur) {
6487ec681f3Smrg		cur = calloc(sizeof *cur, 1);
6497ec681f3Smrg		cur->name = strdup(name);
6507ec681f3Smrg		ADDARRAY(db->groups, cur);
6517ec681f3Smrg	}
6527ec681f3Smrg	xmlNode *chain = node->children;
6537ec681f3Smrg	while (chain) {
6547ec681f3Smrg		struct rnndelem *delem;
6557ec681f3Smrg		if (chain->type != XML_ELEMENT_NODE) {
6567ec681f3Smrg		} else if ((delem = trydelem(db, file, chain))) {
6577ec681f3Smrg			ADDARRAY(cur->subelems, delem);
6587ec681f3Smrg		} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
6597ec681f3Smrg			rnn_err(db, "%s:%d: wrong tag in group: <%s>\n", file, chain->line, chain->name);
6607ec681f3Smrg		}
6617ec681f3Smrg		chain = chain->next;
6627ec681f3Smrg	}
6637ec681f3Smrg}
6647ec681f3Smrg
6657ec681f3Smrgstatic void parsedomain(struct rnndb *db, char *file, xmlNode *node) {
6667ec681f3Smrg	xmlAttr *attr = node->properties;
6677ec681f3Smrg	char *name = 0;
6687ec681f3Smrg	uint64_t size = 0; int width = 8;
6697ec681f3Smrg	int bare = 0;
6707ec681f3Smrg	char *prefixstr = 0;
6717ec681f3Smrg	char *varsetstr = 0;
6727ec681f3Smrg	char *variantsstr = 0;
6737ec681f3Smrg	int i;
6747ec681f3Smrg	while (attr) {
6757ec681f3Smrg		if (!strcmp(attr->name, "name")) {
6767ec681f3Smrg			name = getattrib(db, file, node->line, attr);
6777ec681f3Smrg		} else if (!strcmp(attr->name, "bare")) {
6787ec681f3Smrg			bare = getboolattrib(db, file, node->line, attr);
6797ec681f3Smrg		} else if (!strcmp(attr->name, "size")) {
6807ec681f3Smrg			size = getnumattrib(db, file, node->line, attr);
6817ec681f3Smrg		} else if (!strcmp(attr->name, "width")) {
6827ec681f3Smrg			width = getnumattrib(db, file, node->line, attr);
6837ec681f3Smrg		} else if (!strcmp(attr->name, "prefix")) {
6847ec681f3Smrg			prefixstr = strdup(getattrib(db, file, node->line, attr));
6857ec681f3Smrg		} else if (!strcmp(attr->name, "varset")) {
6867ec681f3Smrg			varsetstr = strdup(getattrib(db, file, node->line, attr));
6877ec681f3Smrg		} else if (!strcmp(attr->name, "variants")) {
6887ec681f3Smrg			variantsstr = strdup(getattrib(db, file, node->line, attr));
6897ec681f3Smrg		} else {
6907ec681f3Smrg			rnn_err(db, "%s:%d: wrong attribute \"%s\" for domain\n", file, node->line, attr->name);
6917ec681f3Smrg		}
6927ec681f3Smrg		attr = attr->next;
6937ec681f3Smrg	}
6947ec681f3Smrg	if (!name) {
6957ec681f3Smrg		rnn_err(db, "%s:%d: nameless domain\n", file, node->line);
6967ec681f3Smrg		return;
6977ec681f3Smrg	}
6987ec681f3Smrg	struct rnndomain *cur = 0;
6997ec681f3Smrg	for (i = 0; i < db->domainsnum; i++)
7007ec681f3Smrg		if (!strcmp(db->domains[i]->name, name)) {
7017ec681f3Smrg			cur = db->domains[i];
7027ec681f3Smrg			break;
7037ec681f3Smrg		}
7047ec681f3Smrg	if (cur) {
7057ec681f3Smrg		if (strdiff(cur->varinfo.prefixstr, prefixstr) ||
7067ec681f3Smrg				strdiff(cur->varinfo.varsetstr, varsetstr) ||
7077ec681f3Smrg				strdiff(cur->varinfo.variantsstr, variantsstr) ||
7087ec681f3Smrg				cur->width != width ||
7097ec681f3Smrg				cur->bare != bare ||
7107ec681f3Smrg				(size && cur->size && size != cur->size)) {
7117ec681f3Smrg			rnn_err(db, "%s:%d: merge fail for domain %s\n", file, node->line, node->name);
7127ec681f3Smrg		} else {
7137ec681f3Smrg			if (size)
7147ec681f3Smrg				cur->size = size;
7157ec681f3Smrg		}
7167ec681f3Smrg	} else {
7177ec681f3Smrg		cur = calloc(sizeof *cur, 1);
7187ec681f3Smrg		cur->name = strdup(name);
7197ec681f3Smrg		cur->bare = bare;
7207ec681f3Smrg		cur->width = width;
7217ec681f3Smrg		cur->size = size;
7227ec681f3Smrg		cur->varinfo.prefixstr = prefixstr;
7237ec681f3Smrg		cur->varinfo.varsetstr = varsetstr;
7247ec681f3Smrg		cur->varinfo.variantsstr = variantsstr;
7257ec681f3Smrg		cur->file = file;
7267ec681f3Smrg		ADDARRAY(db->domains, cur);
7277ec681f3Smrg	}
7287ec681f3Smrg	xmlNode *chain = node->children;
7297ec681f3Smrg	while (chain) {
7307ec681f3Smrg		struct rnndelem *delem;
7317ec681f3Smrg		if (chain->type != XML_ELEMENT_NODE) {
7327ec681f3Smrg		} else if ((delem = trydelem(db, file, chain))) {
7337ec681f3Smrg			ADDARRAY(cur->subelems, delem);
7347ec681f3Smrg		} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
7357ec681f3Smrg			rnn_err(db, "%s:%d: wrong tag in domain: <%s>\n", file, chain->line, chain->name);
7367ec681f3Smrg		}
7377ec681f3Smrg		chain = chain->next;
7387ec681f3Smrg	}
7397ec681f3Smrg}
7407ec681f3Smrg
7417ec681f3Smrgstatic void parsecopyright(struct rnndb *db, char *file, xmlNode *node) {
7427ec681f3Smrg	struct rnncopyright* copyright = &db->copyright;
7437ec681f3Smrg	xmlAttr *attr = node->properties;
7447ec681f3Smrg	while (attr) {
7457ec681f3Smrg		if (!strcmp(attr->name, "year")) {
7467ec681f3Smrg			unsigned firstyear = getnumattrib(db, file, node->line, attr);
7477ec681f3Smrg			if(!copyright->firstyear || firstyear < copyright->firstyear)
7487ec681f3Smrg				copyright->firstyear = firstyear;
7497ec681f3Smrg		} else {
7507ec681f3Smrg			rnn_err(db, "%s:%d: wrong attribute \"%s\" for copyright\n", file, node->line, attr->name);
7517ec681f3Smrg		}
7527ec681f3Smrg		attr = attr->next;
7537ec681f3Smrg	}
7547ec681f3Smrg	xmlNode *chain = node->children;
7557ec681f3Smrg	while (chain) {
7567ec681f3Smrg		if (chain->type != XML_ELEMENT_NODE) {
7577ec681f3Smrg		} else if (!strcmp(chain->name, "license"))
7587ec681f3Smrg			if(copyright->license) {
7597ec681f3Smrg				if(strcmp(copyright->license, node->content)) {
7607ec681f3Smrg					fprintf(stderr, "fatal error: multiple different licenses specified!\n");
7617ec681f3Smrg					abort(); /* TODO: do something better here, but headergen, xml2html, etc. should not produce anything in this case */
7627ec681f3Smrg				}
7637ec681f3Smrg			} else
7647ec681f3Smrg				copyright->license = getcontent(chain);
7657ec681f3Smrg		else if (!strcmp(chain->name, "author")) {
7667ec681f3Smrg			struct rnnauthor* author = calloc(sizeof *author, 1);
7677ec681f3Smrg			xmlAttr* authorattr = chain->properties;
7687ec681f3Smrg			xmlNode *authorchild = chain->children;
7697ec681f3Smrg			author->contributions = getcontent(chain);
7707ec681f3Smrg			while (authorattr) {
7717ec681f3Smrg				if (!strcmp(authorattr->name, "name"))
7727ec681f3Smrg					author->name = strdup(getattrib(db, file, chain->line, authorattr));
7737ec681f3Smrg				else if (!strcmp(authorattr->name, "email"))
7747ec681f3Smrg					author->email = strdup(getattrib(db, file, chain->line, authorattr));
7757ec681f3Smrg				else {
7767ec681f3Smrg					rnn_err(db, "%s:%d: wrong attribute \"%s\" for author\n", file, chain->line, authorattr->name);
7777ec681f3Smrg				}
7787ec681f3Smrg				authorattr = authorattr->next;
7797ec681f3Smrg			}
7807ec681f3Smrg			while(authorchild)  {
7817ec681f3Smrg				if (authorchild->type != XML_ELEMENT_NODE) {
7827ec681f3Smrg				} else if (!strcmp(authorchild->name, "nick")) {
7837ec681f3Smrg					xmlAttr* nickattr = authorchild->properties;
7847ec681f3Smrg					char* nickname = 0;
7857ec681f3Smrg					while(nickattr) {
7867ec681f3Smrg						if (!strcmp(nickattr->name, "name"))
7877ec681f3Smrg							nickname = strdup(getattrib(db, file, authorchild->line, nickattr));
7887ec681f3Smrg						else {
7897ec681f3Smrg							rnn_err(db, "%s:%d: wrong attribute \"%s\" for nick\n", file, authorchild->line, nickattr->name);
7907ec681f3Smrg						}
7917ec681f3Smrg						nickattr = nickattr->next;
7927ec681f3Smrg					}
7937ec681f3Smrg					if(!nickname) {
7947ec681f3Smrg						rnn_err(db, "%s:%d: missing \"name\" attribute for nick\n", file, authorchild->line);
7957ec681f3Smrg					} else
7967ec681f3Smrg						ADDARRAY(author->nicknames, nickname);
7977ec681f3Smrg				} else {
7987ec681f3Smrg					rnn_err(db, "%s:%d: wrong tag in author: <%s>\n", file, authorchild->line, authorchild->name);
7997ec681f3Smrg				}
8007ec681f3Smrg				authorchild = authorchild->next;
8017ec681f3Smrg			}
8027ec681f3Smrg			ADDARRAY(copyright->authors, author);
8037ec681f3Smrg		} else {
8047ec681f3Smrg			rnn_err(db, "%s:%d: wrong tag in copyright: <%s>\n", file, chain->line, chain->name);
8057ec681f3Smrg		}
8067ec681f3Smrg		chain = chain->next;
8077ec681f3Smrg	}
8087ec681f3Smrg}
8097ec681f3Smrg
8107ec681f3Smrgstatic int trytop (struct rnndb *db, char *file, xmlNode *node) {
8117ec681f3Smrg	if (!strcmp(node->name, "enum")) {
8127ec681f3Smrg		parseenum(db, file, node);
8137ec681f3Smrg		return 1;
8147ec681f3Smrg	} else if (!strcmp(node->name, "bitset")) {
8157ec681f3Smrg		parsebitset(db, file, node);
8167ec681f3Smrg		return 1;
8177ec681f3Smrg	} else if (!strcmp(node->name, "group")) {
8187ec681f3Smrg		parsegroup(db, file, node);
8197ec681f3Smrg		return 1;
8207ec681f3Smrg	} else if (!strcmp(node->name, "domain")) {
8217ec681f3Smrg		parsedomain(db, file, node);
8227ec681f3Smrg		return 1;
8237ec681f3Smrg	} else if (!strcmp(node->name, "spectype")) {
8247ec681f3Smrg		parsespectype(db, file, node);
8257ec681f3Smrg		return 1;
8267ec681f3Smrg	} else if (!strcmp(node->name, "import")) {
8277ec681f3Smrg		xmlAttr *attr = node->properties;
8287ec681f3Smrg		char *subfile = 0;
8297ec681f3Smrg		while (attr) {
8307ec681f3Smrg			if (!strcmp(attr->name, "file")) {
8317ec681f3Smrg				subfile = getattrib(db, file, node->line, attr);
8327ec681f3Smrg			} else {
8337ec681f3Smrg				rnn_err(db, "%s:%d: wrong attribute \"%s\" for import\n", file, node->line, attr->name);
8347ec681f3Smrg			}
8357ec681f3Smrg			attr = attr->next;
8367ec681f3Smrg		}
8377ec681f3Smrg		if (!subfile) {
8387ec681f3Smrg			rnn_err(db, "%s:%d: missing \"file\" attribute for import\n", file, node->line);
8397ec681f3Smrg		} else {
8407ec681f3Smrg			rnn_parsefile(db, subfile);
8417ec681f3Smrg		}
8427ec681f3Smrg		return 1;
8437ec681f3Smrg	} else if (!strcmp(node->name, "copyright")) {
8447ec681f3Smrg		parsecopyright(db, file, node);
8457ec681f3Smrg		return 1;
8467ec681f3Smrg	}
8477ec681f3Smrg	return 0;
8487ec681f3Smrg}
8497ec681f3Smrg
8507ec681f3Smrgstatic char * find_file(const char *file_orig)
8517ec681f3Smrg{
8527ec681f3Smrg	const char *rnn_path = getenv("RNN_PATH");
8537ec681f3Smrg	char *fname;
8547ec681f3Smrg
8557ec681f3Smrg	if (!rnn_path)
8567ec681f3Smrg		rnn_path = RNN_DEF_PATH;
8577ec681f3Smrg
8587ec681f3Smrg	FILE *file = find_in_path(file_orig, rnn_path, &fname);
8597ec681f3Smrg	if (!file) {
8607ec681f3Smrg		fprintf (stderr, "%s: couldn't find database file. Please set the env var RNN_PATH.\n", file_orig);
8617ec681f3Smrg		return NULL;
8627ec681f3Smrg	}
8637ec681f3Smrg	fclose(file);
8647ec681f3Smrg
8657ec681f3Smrg	return fname;
8667ec681f3Smrg}
8677ec681f3Smrg
8687ec681f3Smrgstatic int validate_doc(struct rnndb *db, xmlDocPtr doc, xmlNodePtr database)
8697ec681f3Smrg{
8707ec681f3Smrg	/* find the schemaLocation property: */
8717ec681f3Smrg	xmlAttrPtr attr = database->properties;
8727ec681f3Smrg	const char *schema_name = NULL;
8737ec681f3Smrg	char *schema_path;
8747ec681f3Smrg
8757ec681f3Smrg	while (attr) {
8767ec681f3Smrg		if (!strcmp(attr->name, "schemaLocation")) {
8777ec681f3Smrg			xmlNodePtr data = attr->children;
8787ec681f3Smrg			schema_name = data->content;
8797ec681f3Smrg			/* we expect this to look like <namespace url> schema.xsd.. I think
8807ec681f3Smrg			 * technically it is supposed to be just a URL, but that doesn't
8817ec681f3Smrg			 * quite match up to what we do.. Just skip over everything up to
8827ec681f3Smrg			 * and including the first whitespace character:
8837ec681f3Smrg			 */
8847ec681f3Smrg			while (schema_name && (schema_name[0] != ' '))
8857ec681f3Smrg				schema_name++;
8867ec681f3Smrg			schema_name++;
8877ec681f3Smrg			break;
8887ec681f3Smrg		}
8897ec681f3Smrg	}
8907ec681f3Smrg
8917ec681f3Smrg	if (!schema_name) {
8927ec681f3Smrg		rnn_err(db, "could not find schema.  Missing schemaLocation?");
8937ec681f3Smrg		return 0;
8947ec681f3Smrg	}
8957ec681f3Smrg
8967ec681f3Smrg	schema_path = find_file(schema_name);
8977ec681f3Smrg	if (!schema_path) {
8987ec681f3Smrg		rnn_err(db, "%s: couldn't find database file. Please set the env var RNN_PATH.\n", schema_name);
8997ec681f3Smrg		return 0;
9007ec681f3Smrg	}
9017ec681f3Smrg
9027ec681f3Smrg	xmlSchemaParserCtxtPtr parser = xmlSchemaNewParserCtxt(schema_path);
9037ec681f3Smrg	xmlSchemaPtr schema = xmlSchemaParse(parser);
9047ec681f3Smrg	xmlSchemaValidCtxtPtr validCtxt = xmlSchemaNewValidCtxt(schema);
9057ec681f3Smrg	int ret = xmlSchemaValidateDoc(validCtxt, doc);
9067ec681f3Smrg
9077ec681f3Smrg	xmlSchemaFreeValidCtxt(validCtxt);
9087ec681f3Smrg	xmlSchemaFree(schema);
9097ec681f3Smrg	xmlSchemaFreeParserCtxt(parser);
9107ec681f3Smrg
9117ec681f3Smrg	free(schema_path);
9127ec681f3Smrg
9137ec681f3Smrg	return ret;
9147ec681f3Smrg}
9157ec681f3Smrg
9167ec681f3Smrgvoid rnn_parsefile (struct rnndb *db, char *file_orig) {
9177ec681f3Smrg	int i;
9187ec681f3Smrg	char *fname;
9197ec681f3Smrg
9207ec681f3Smrg	fname = find_file(file_orig);
9217ec681f3Smrg	if (!fname) {
9227ec681f3Smrg		db->estatus = 1;
9237ec681f3Smrg		return;
9247ec681f3Smrg	}
9257ec681f3Smrg
9267ec681f3Smrg	for (i = 0; i < db->filesnum; i++)
9277ec681f3Smrg		if (!strcmp(db->files[i], fname))
9287ec681f3Smrg			return;
9297ec681f3Smrg
9307ec681f3Smrg	ADDARRAY(db->files, fname);
9317ec681f3Smrg	xmlDocPtr doc = xmlParseFile(fname);
9327ec681f3Smrg	if (!doc) {
9337ec681f3Smrg		rnn_err(db, "%s: couldn't open database file. Please set the env var RNN_PATH.\n", fname);
9347ec681f3Smrg		return;
9357ec681f3Smrg	}
9367ec681f3Smrg	xmlNode *root = doc->children;
9377ec681f3Smrg	while (root) {
9387ec681f3Smrg		if (root->type != XML_ELEMENT_NODE) {
9397ec681f3Smrg		} else if (strcmp(root->name, "database")) {
9407ec681f3Smrg			rnn_err(db, "%s:%d: wrong top-level tag <%s>\n", fname, root->line, root->name);
9417ec681f3Smrg		} else {
9427ec681f3Smrg			xmlNode *chain = root->children;
9437ec681f3Smrg			if (validate_doc(db, doc, root)) {
9447ec681f3Smrg				rnn_err(db, "%s: database file has errors\n", fname);
9457ec681f3Smrg				return;
9467ec681f3Smrg			}
9477ec681f3Smrg			while (chain) {
9487ec681f3Smrg				if (chain->type != XML_ELEMENT_NODE) {
9497ec681f3Smrg				} else if (!trytop(db, fname, chain) && !trydoc(db, fname, chain)) {
9507ec681f3Smrg					rnn_err(db, "%s:%d: wrong tag in database: <%s>\n", fname, chain->line, chain->name);
9517ec681f3Smrg				}
9527ec681f3Smrg				chain = chain->next;
9537ec681f3Smrg			}
9547ec681f3Smrg		}
9557ec681f3Smrg		root = root->next;
9567ec681f3Smrg	}
9577ec681f3Smrg	xmlFreeDoc(doc);
9587ec681f3Smrg}
9597ec681f3Smrg
9607ec681f3Smrgstatic struct rnnvalue *copyvalue (struct rnnvalue *val, char *file) {
9617ec681f3Smrg	struct rnnvalue *res = calloc (sizeof *res, 1);
9627ec681f3Smrg	res->name = val->name;
9637ec681f3Smrg	res->valvalid = val->valvalid;
9647ec681f3Smrg	res->value = val->value;
9657ec681f3Smrg	res->varinfo = val->varinfo;
9667ec681f3Smrg	res->file = file;
9677ec681f3Smrg	return res;
9687ec681f3Smrg}
9697ec681f3Smrg
9707ec681f3Smrgstatic struct rnnbitfield *copybitfield (struct rnnbitfield *bf, char *file);
9717ec681f3Smrg
9727ec681f3Smrg
9737ec681f3Smrgstatic void copytypeinfo (struct rnntypeinfo *dst, struct rnntypeinfo *src, char *file) {
9747ec681f3Smrg	int i;
9757ec681f3Smrg	dst->name = src->name;
9767ec681f3Smrg	dst->shr = src->shr;
9777ec681f3Smrg	dst->low = src->low;
9787ec681f3Smrg	dst->high = src->high;
9797ec681f3Smrg	dst->min = src->min;
9807ec681f3Smrg	dst->max = src->max;
9817ec681f3Smrg	dst->align = src->align;
9827ec681f3Smrg	dst->addvariant = src->addvariant;
9837ec681f3Smrg	for (i = 0; i < src->valsnum; i++)
9847ec681f3Smrg		ADDARRAY(dst->vals, copyvalue(src->vals[i], file));
9857ec681f3Smrg	for (i = 0; i < src->bitfieldsnum; i++)
9867ec681f3Smrg		ADDARRAY(dst->bitfields, copybitfield(src->bitfields[i], file));
9877ec681f3Smrg}
9887ec681f3Smrg
9897ec681f3Smrgstatic struct rnnbitfield *copybitfield (struct rnnbitfield *bf, char *file) {
9907ec681f3Smrg	struct rnnbitfield *res = calloc (sizeof *res, 1);
9917ec681f3Smrg	res->name = bf->name;
9927ec681f3Smrg	res->varinfo = bf->varinfo;
9937ec681f3Smrg	res->file = file;
9947ec681f3Smrg	copytypeinfo(&res->typeinfo, &bf->typeinfo, file);
9957ec681f3Smrg	return res;
9967ec681f3Smrg}
9977ec681f3Smrg
9987ec681f3Smrgstatic struct rnndelem *copydelem (struct rnndelem *elem, char *file) {
9997ec681f3Smrg	struct rnndelem *res = calloc (sizeof *res, 1);
10007ec681f3Smrg	res->type = elem->type;
10017ec681f3Smrg	res->name = elem->name;
10027ec681f3Smrg	res->width = elem->width;
10037ec681f3Smrg	res->access = elem->access;
10047ec681f3Smrg	res->offset = elem->offset;
10057ec681f3Smrg	res->length = elem->length;
10067ec681f3Smrg	res->stride = elem->stride;
10077ec681f3Smrg	res->varinfo = elem->varinfo;
10087ec681f3Smrg	res->file = file;
10097ec681f3Smrg	copytypeinfo(&res->typeinfo, &elem->typeinfo, file);
10107ec681f3Smrg	int i;
10117ec681f3Smrg	for (i = 0; i < elem->subelemsnum; i++)
10127ec681f3Smrg		ADDARRAY(res->subelems, copydelem(elem->subelems[i], file));
10137ec681f3Smrg	for (i = 0; i < elem->offsetsnum; i++)
10147ec681f3Smrg		ADDARRAY(res->offsets, elem->offsets[i]);
10157ec681f3Smrg	return res;
10167ec681f3Smrg}
10177ec681f3Smrg
10187ec681f3Smrgstatic struct rnnvarset *copyvarset (struct rnnvarset *varset) {
10197ec681f3Smrg	struct rnnvarset *res = calloc(sizeof *res, 1);
10207ec681f3Smrg	res->venum = varset->venum;
10217ec681f3Smrg	res->variants = calloc(sizeof *res->variants, res->venum->valsnum);
10227ec681f3Smrg	int i;
10237ec681f3Smrg	for (i = 0; i < res->venum->valsnum; i++)
10247ec681f3Smrg		res->variants[i] = varset->variants[i];
10257ec681f3Smrg	return res;
10267ec681f3Smrg}
10277ec681f3Smrg
10287ec681f3Smrgstatic void prepenum(struct rnndb *db, struct rnnenum *en);
10297ec681f3Smrg
10307ec681f3Smrgstatic int findvidx (struct rnndb *db, struct rnnenum *en, char *name) {
10317ec681f3Smrg	int i;
10327ec681f3Smrg	for (i = 0; i < en->valsnum; i++)
10337ec681f3Smrg		if (!strcmp(en->vals[i]->name, name))
10347ec681f3Smrg			return i;
10357ec681f3Smrg	rnn_err(db, "Cannot find variant %s in enum %s!\n", name, en->name);
10367ec681f3Smrg	return -1;
10377ec681f3Smrg}
10387ec681f3Smrg
10397ec681f3Smrgstatic void prepvarinfo (struct rnndb *db, char *what, struct rnnvarinfo *vi, struct rnnvarinfo *parent) {
10407ec681f3Smrg	if (parent)
10417ec681f3Smrg		vi->prefenum = parent->prefenum;
10427ec681f3Smrg	if (vi->prefixstr) {
10437ec681f3Smrg		if (!strcmp(vi->prefixstr, "none"))
10447ec681f3Smrg			vi->prefenum = 0;
10457ec681f3Smrg		else
10467ec681f3Smrg			vi->prefenum = rnn_findenum(db, vi->prefixstr); // XXX
10477ec681f3Smrg	}
10487ec681f3Smrg	int i;
10497ec681f3Smrg	if (parent)
10507ec681f3Smrg		for (i = 0; i < parent->varsetsnum; i++)
10517ec681f3Smrg			ADDARRAY(vi->varsets, copyvarset(parent->varsets[i]));
10527ec681f3Smrg	struct rnnenum *varset = vi->prefenum;
10537ec681f3Smrg	if (!varset && !vi->varsetstr && parent)
10547ec681f3Smrg		vi->varsetstr = parent->varsetstr;
10557ec681f3Smrg	if (vi->varsetstr)
10567ec681f3Smrg		varset = rnn_findenum(db, vi->varsetstr);
10577ec681f3Smrg	if (vi->variantsstr) {
10587ec681f3Smrg		char *vars = vi->variantsstr;
10597ec681f3Smrg		if (!varset) {
10607ec681f3Smrg			rnn_err(db, "%s: tried to use variants without active varset!\n", what);
10617ec681f3Smrg			return;
10627ec681f3Smrg		}
10637ec681f3Smrg		struct rnnvarset *vs = 0;
10647ec681f3Smrg		int nvars = varset->valsnum;
10657ec681f3Smrg		for (i = 0; i < vi->varsetsnum; i++)
10667ec681f3Smrg			if (vi->varsets[i]->venum == varset) {
10677ec681f3Smrg				vs = vi->varsets[i];
10687ec681f3Smrg				break;
10697ec681f3Smrg			}
10707ec681f3Smrg		if (!vs) {
10717ec681f3Smrg			vs = calloc (sizeof *vs, 1);
10727ec681f3Smrg			vs->venum = varset;
10737ec681f3Smrg			vs->variants = calloc(sizeof *vs->variants, nvars);
10747ec681f3Smrg			for (i = 0; i < nvars; i++)
10757ec681f3Smrg				vs->variants[i] = 1;
10767ec681f3Smrg			ADDARRAY(vi->varsets, vs);
10777ec681f3Smrg		}
10787ec681f3Smrg		while (1) {
10797ec681f3Smrg			while (*vars == ' ') vars++;
10807ec681f3Smrg			if (*vars == 0)
10817ec681f3Smrg				break;
10827ec681f3Smrg			char *split = vars;
10837ec681f3Smrg			while (*split != ':' && *split != '-' && *split != ' '  && *split != 0)
10847ec681f3Smrg				split++;
10857ec681f3Smrg			char *first = 0;
10867ec681f3Smrg			if (split != vars)
10877ec681f3Smrg				first = strndup(vars, split-vars);
10887ec681f3Smrg			if (*split == ' ' || *split == 0) {
10897ec681f3Smrg				int idx = findvidx(db, varset, first);
10907ec681f3Smrg				if (idx != -1)
10917ec681f3Smrg					vs->variants[idx] |= 2;
10927ec681f3Smrg				vars = split;
10937ec681f3Smrg			} else {
10947ec681f3Smrg				char *end = split+1;
10957ec681f3Smrg				while (*end != ' '  && *end != 0)
10967ec681f3Smrg					end++;
10977ec681f3Smrg				char *second = 0;
10987ec681f3Smrg				if (end != split+1)
10997ec681f3Smrg					second = strndup(split+1, end-split-1);
11007ec681f3Smrg				int idx1 = 0;
11017ec681f3Smrg				if (first)
11027ec681f3Smrg					idx1 = findvidx(db, varset, first);
11037ec681f3Smrg				int idx2 = nvars;
11047ec681f3Smrg				if (second) {
11057ec681f3Smrg					idx2 = findvidx(db, varset, second);
11067ec681f3Smrg					if (*split == '-')
11077ec681f3Smrg						idx2++;
11087ec681f3Smrg				}
11097ec681f3Smrg				if (idx1 != -1 && idx2 != -1)
11107ec681f3Smrg					for (i = idx1; i < idx2; i++)
11117ec681f3Smrg						vs->variants[i] |= 2;
11127ec681f3Smrg				vars = end;
11137ec681f3Smrg				free(second);
11147ec681f3Smrg			}
11157ec681f3Smrg			free(first);
11167ec681f3Smrg		}
11177ec681f3Smrg		vi->dead = 1;
11187ec681f3Smrg		for (i = 0; i < nvars; i++) {
11197ec681f3Smrg			vs->variants[i] = (vs->variants[i] == 3);
11207ec681f3Smrg			if (vs->variants[i])
11217ec681f3Smrg				vi->dead = 0;
11227ec681f3Smrg		}
11237ec681f3Smrg	}
11247ec681f3Smrg	if (vi->dead)
11257ec681f3Smrg		return;
11267ec681f3Smrg	if (vi->prefenum) {
11277ec681f3Smrg		struct rnnvarset *vs = 0;
11287ec681f3Smrg		for (i = 0; i < vi->varsetsnum; i++)
11297ec681f3Smrg			if (vi->varsets[i]->venum == vi->prefenum) {
11307ec681f3Smrg				vs = vi->varsets[i];
11317ec681f3Smrg				break;
11327ec681f3Smrg			}
11337ec681f3Smrg		if (vs) {
11347ec681f3Smrg			for (i = 0; i < vi->prefenum->valsnum; i++)
11357ec681f3Smrg				if (vs->variants[i]) {
11367ec681f3Smrg					vi->prefix = vi->prefenum->vals[i]->name;
11377ec681f3Smrg					return;
11387ec681f3Smrg				}
11397ec681f3Smrg		} else {
11407ec681f3Smrg			vi->prefix = vi->prefenum->vals[0]->name;
11417ec681f3Smrg		}
11427ec681f3Smrg	}
11437ec681f3Smrg}
11447ec681f3Smrg
11457ec681f3Smrgstatic void prepvalue(struct rnndb *db, struct rnnvalue *val, char *prefix, struct rnnvarinfo *parvi) {
11467ec681f3Smrg	val->fullname = catstr(prefix, val->name);
11477ec681f3Smrg	prepvarinfo (db, val->fullname, &val->varinfo, parvi);
11487ec681f3Smrg	if (val->varinfo.dead)
11497ec681f3Smrg		return;
11507ec681f3Smrg	if (val->varinfo.prefix)
11517ec681f3Smrg		val->fullname = catstr(val->varinfo.prefix, val->fullname);
11527ec681f3Smrg}
11537ec681f3Smrg
11547ec681f3Smrgstatic void prepbitfield(struct rnndb *db, struct rnnbitfield *bf, char *prefix, struct rnnvarinfo *parvi);
11557ec681f3Smrg
11567ec681f3Smrgstatic void preptypeinfo(struct rnndb *db, struct rnntypeinfo *ti, char *prefix, struct rnnvarinfo *vi, char *file) {
11577ec681f3Smrg	int i;
11587ec681f3Smrg	if (ti->name) {
11597ec681f3Smrg		struct rnnenum *en = rnn_findenum (db, ti->name);
11607ec681f3Smrg		struct rnnbitset *bs = rnn_findbitset (db, ti->name);
11617ec681f3Smrg		struct rnnspectype *st = rnn_findspectype (db, ti->name);
11627ec681f3Smrg		if (en) {
11637ec681f3Smrg			if (en->isinline) {
11647ec681f3Smrg				ti->type = RNN_TTYPE_INLINE_ENUM;
11657ec681f3Smrg				int j;
11667ec681f3Smrg				for (j = 0; j < en->valsnum; j++)
11677ec681f3Smrg					ADDARRAY(ti->vals, copyvalue(en->vals[j], file));
11687ec681f3Smrg			} else {
11697ec681f3Smrg				ti->type = RNN_TTYPE_ENUM;
11707ec681f3Smrg				ti->eenum = en;
11717ec681f3Smrg			}
11727ec681f3Smrg		} else if (bs) {
11737ec681f3Smrg			if (bs->isinline) {
11747ec681f3Smrg				ti->type = RNN_TTYPE_INLINE_BITSET;
11757ec681f3Smrg				int j;
11767ec681f3Smrg				for (j = 0; j < bs->bitfieldsnum; j++)
11777ec681f3Smrg					ADDARRAY(ti->bitfields, copybitfield(bs->bitfields[j], file));
11787ec681f3Smrg			} else {
11797ec681f3Smrg				ti->type = RNN_TTYPE_BITSET;
11807ec681f3Smrg				ti->ebitset = bs;
11817ec681f3Smrg			}
11827ec681f3Smrg		} else if (st) {
11837ec681f3Smrg			ti->type = RNN_TTYPE_SPECTYPE;
11847ec681f3Smrg			ti->spectype = st;
11857ec681f3Smrg		} else if (!strcmp(ti->name, "hex")) {
11867ec681f3Smrg			ti->type = RNN_TTYPE_HEX;
11877ec681f3Smrg		} else if (!strcmp(ti->name, "float")) {
11887ec681f3Smrg			ti->type = RNN_TTYPE_FLOAT;
11897ec681f3Smrg		} else if (!strcmp(ti->name, "uint")) {
11907ec681f3Smrg			ti->type = RNN_TTYPE_UINT;
11917ec681f3Smrg		} else if (!strcmp(ti->name, "int")) {
11927ec681f3Smrg			ti->type = RNN_TTYPE_INT;
11937ec681f3Smrg		} else if (!strcmp(ti->name, "boolean")) {
11947ec681f3Smrg			ti->type = RNN_TTYPE_BOOLEAN;
11957ec681f3Smrg		} else if (!strcmp(ti->name, "bitfield")) {
11967ec681f3Smrg			ti->type = RNN_TTYPE_INLINE_BITSET;
11977ec681f3Smrg		} else if (!strcmp(ti->name, "enum")) {
11987ec681f3Smrg			ti->type = RNN_TTYPE_INLINE_ENUM;
11997ec681f3Smrg		} else if (!strcmp(ti->name, "fixed")) {
12007ec681f3Smrg			ti->type = RNN_TTYPE_FIXED;
12017ec681f3Smrg		} else if (!strcmp(ti->name, "ufixed")) {
12027ec681f3Smrg			ti->type = RNN_TTYPE_UFIXED;
12037ec681f3Smrg		} else if (!strcmp(ti->name, "a3xx_regid")) {
12047ec681f3Smrg			ti->type = RNN_TTYPE_A3XX_REGID;
12057ec681f3Smrg		} else if (!strcmp(ti->name, "waddress") || !strcmp(ti->name, "address")) {
12067ec681f3Smrg			ti->type = RNN_TTYPE_HEX;
12077ec681f3Smrg		} else {
12087ec681f3Smrg			ti->type = RNN_TTYPE_HEX;
12097ec681f3Smrg			rnn_err(db, "%s: unknown type %s\n", prefix, ti->name);
12107ec681f3Smrg		}
12117ec681f3Smrg	} else if (ti->bitfieldsnum) {
12127ec681f3Smrg		ti->name = "bitfield";
12137ec681f3Smrg		ti->type = RNN_TTYPE_INLINE_BITSET;
12147ec681f3Smrg	} else if (ti->valsnum) {
12157ec681f3Smrg		ti->name = "enum";
12167ec681f3Smrg		ti->type = RNN_TTYPE_INLINE_ENUM;
12177ec681f3Smrg	} else if (ti->low == 0 && ti->high == 0) {
12187ec681f3Smrg		ti->name = "boolean";
12197ec681f3Smrg		ti->type = RNN_TTYPE_BOOLEAN;
12207ec681f3Smrg	} else {
12217ec681f3Smrg		ti->name = "hex";
12227ec681f3Smrg		ti->type = RNN_TTYPE_HEX;
12237ec681f3Smrg	}
12247ec681f3Smrg	if (ti->addvariant && ti->type != RNN_TTYPE_ENUM) {
12257ec681f3Smrg		rnn_err(db, "%s: addvariant specified on non-enum type %s\n", prefix, ti->name);
12267ec681f3Smrg	}
12277ec681f3Smrg	for (i = 0; i < ti->bitfieldsnum; i++)
12287ec681f3Smrg		prepbitfield(db,  ti->bitfields[i], prefix, vi);
12297ec681f3Smrg	for (i = 0; i < ti->valsnum; i++)
12307ec681f3Smrg		prepvalue(db, ti->vals[i], prefix, vi);
12317ec681f3Smrg}
12327ec681f3Smrg
12337ec681f3Smrgstatic void prepbitfield(struct rnndb *db, struct rnnbitfield *bf, char *prefix, struct rnnvarinfo *parvi) {
12347ec681f3Smrg	bf->fullname = catstr(prefix, bf->name);
12357ec681f3Smrg	prepvarinfo (db, bf->fullname, &bf->varinfo, parvi);
12367ec681f3Smrg	if (bf->varinfo.dead)
12377ec681f3Smrg		return;
12387ec681f3Smrg	preptypeinfo(db, &bf->typeinfo, bf->fullname, &bf->varinfo, bf->file);
12397ec681f3Smrg	if (bf->varinfo.prefix)
12407ec681f3Smrg		bf->fullname = catstr(bf->varinfo.prefix, bf->fullname);
12417ec681f3Smrg}
12427ec681f3Smrg
12437ec681f3Smrgstatic void prepdelem(struct rnndb *db, struct rnndelem *elem, char *prefix, struct rnnvarinfo *parvi, int width) {
12447ec681f3Smrg	if (elem->type == RNN_ETYPE_USE_GROUP) {
12457ec681f3Smrg		int i;
12467ec681f3Smrg		struct rnngroup *gr = 0;
12477ec681f3Smrg		for (i = 0; i < db->groupsnum; i++)
12487ec681f3Smrg			if (!strcmp(db->groups[i]->name, elem->name)) {
12497ec681f3Smrg				gr = db->groups[i];
12507ec681f3Smrg				break;
12517ec681f3Smrg			}
12527ec681f3Smrg		if (gr) {
12537ec681f3Smrg			for (i = 0; i < gr->subelemsnum; i++)
12547ec681f3Smrg				ADDARRAY(elem->subelems, copydelem(gr->subelems[i], elem->file));
12557ec681f3Smrg		} else {
12567ec681f3Smrg			rnn_err(db, "group %s not found!\n", elem->name);
12577ec681f3Smrg		}
12587ec681f3Smrg		elem->type = RNN_ETYPE_STRIPE;
12597ec681f3Smrg		elem->length = 1;
12607ec681f3Smrg		elem->name = 0;
12617ec681f3Smrg	}
12627ec681f3Smrg	if (elem->name)
12637ec681f3Smrg		elem->fullname = catstr(prefix, elem->name);
12647ec681f3Smrg	prepvarinfo (db, elem->fullname?elem->fullname:prefix, &elem->varinfo, parvi);
12657ec681f3Smrg	if (elem->varinfo.dead)
12667ec681f3Smrg		return;
12677ec681f3Smrg	if (elem->length != 1 && !elem->stride) {
12687ec681f3Smrg		if (elem->type != RNN_ETYPE_REG) {
12697ec681f3Smrg			rnn_err(db, "%s has non-1 length, but no stride!\n", elem->fullname);
12707ec681f3Smrg		} else {
12717ec681f3Smrg			elem->stride = elem->width/width;
12727ec681f3Smrg		}
12737ec681f3Smrg	}
12747ec681f3Smrg	preptypeinfo(db, &elem->typeinfo, elem->name?elem->fullname:prefix, &elem->varinfo, elem->file);
12757ec681f3Smrg
12767ec681f3Smrg	int i;
12777ec681f3Smrg	for (i = 0; i < elem->subelemsnum; i++)
12787ec681f3Smrg		prepdelem(db,  elem->subelems[i], elem->name?elem->fullname:prefix, &elem->varinfo, width);
12797ec681f3Smrg	if (elem->varinfo.prefix && elem->name)
12807ec681f3Smrg		elem->fullname = catstr(elem->varinfo.prefix, elem->fullname);
12817ec681f3Smrg}
12827ec681f3Smrg
12837ec681f3Smrgstatic void prepdomain(struct rnndb *db, struct rnndomain *dom) {
12847ec681f3Smrg	prepvarinfo (db, dom->name, &dom->varinfo, 0);
12857ec681f3Smrg	int i;
12867ec681f3Smrg	for (i = 0; i < dom->subelemsnum; i++)
12877ec681f3Smrg		prepdelem(db, dom->subelems[i], dom->bare?0:dom->name, &dom->varinfo, dom->width);
12887ec681f3Smrg	dom->fullname = catstr(dom->varinfo.prefix, dom->name);
12897ec681f3Smrg}
12907ec681f3Smrg
12917ec681f3Smrgstatic void prepenum(struct rnndb *db, struct rnnenum *en) {
12927ec681f3Smrg	if (en->prepared)
12937ec681f3Smrg		return;
12947ec681f3Smrg	prepvarinfo (db, en->name, &en->varinfo, 0);
12957ec681f3Smrg	int i;
12967ec681f3Smrg	if (en->isinline)
12977ec681f3Smrg		return;
12987ec681f3Smrg	for (i = 0; i < en->valsnum; i++)
12997ec681f3Smrg		prepvalue(db, en->vals[i], en->bare?0:en->name, &en->varinfo);
13007ec681f3Smrg	en->fullname = catstr(en->varinfo.prefix, en->name);
13017ec681f3Smrg	en->prepared = 1;
13027ec681f3Smrg}
13037ec681f3Smrg
13047ec681f3Smrgstatic void prepbitset(struct rnndb *db, struct rnnbitset *bs) {
13057ec681f3Smrg	prepvarinfo (db, bs->name, &bs->varinfo, 0);
13067ec681f3Smrg	int i;
13077ec681f3Smrg	if (bs->isinline)
13087ec681f3Smrg		return;
13097ec681f3Smrg	for (i = 0; i < bs->bitfieldsnum; i++)
13107ec681f3Smrg		prepbitfield(db, bs->bitfields[i], bs->bare?0:bs->name, &bs->varinfo);
13117ec681f3Smrg	bs->fullname = catstr(bs->varinfo.prefix, bs->name);
13127ec681f3Smrg}
13137ec681f3Smrg
13147ec681f3Smrgstatic void prepspectype(struct rnndb *db, struct rnnspectype *st) {
13157ec681f3Smrg	preptypeinfo(db, &st->typeinfo, st->name, 0, st->file); // XXX doesn't exactly make sense...
13167ec681f3Smrg}
13177ec681f3Smrg
13187ec681f3Smrgvoid rnn_prepdb (struct rnndb *db) {
13197ec681f3Smrg	int i;
13207ec681f3Smrg	for (i = 0; i < db->enumsnum; i++)
13217ec681f3Smrg		prepenum(db, db->enums[i]);
13227ec681f3Smrg	for (i = 0; i < db->bitsetsnum; i++)
13237ec681f3Smrg		prepbitset(db, db->bitsets[i]);
13247ec681f3Smrg	for (i = 0; i < db->domainsnum; i++)
13257ec681f3Smrg		prepdomain(db, db->domains[i]);
13267ec681f3Smrg	for (i = 0; i < db->spectypesnum; i++)
13277ec681f3Smrg		prepspectype(db, db->spectypes[i]);
13287ec681f3Smrg}
13297ec681f3Smrg
13307ec681f3Smrgstruct rnnenum *rnn_findenum (struct rnndb *db, const char *name) {
13317ec681f3Smrg	int i;
13327ec681f3Smrg	for (i = 0; i < db->enumsnum; i++)
13337ec681f3Smrg		if (!strcmp(db->enums[i]->name, name))
13347ec681f3Smrg			return db->enums[i];
13357ec681f3Smrg	return 0;
13367ec681f3Smrg}
13377ec681f3Smrg
13387ec681f3Smrgstruct rnnbitset *rnn_findbitset (struct rnndb *db, const char *name) {
13397ec681f3Smrg	int i;
13407ec681f3Smrg	for (i = 0; i < db->bitsetsnum; i++)
13417ec681f3Smrg		if (!strcmp(db->bitsets[i]->name, name))
13427ec681f3Smrg			return db->bitsets[i];
13437ec681f3Smrg	return 0;
13447ec681f3Smrg}
13457ec681f3Smrg
13467ec681f3Smrgstruct rnndomain *rnn_finddomain (struct rnndb *db, const char *name) {
13477ec681f3Smrg	int i;
13487ec681f3Smrg	for (i = 0; i < db->domainsnum; i++)
13497ec681f3Smrg		if (!strcmp(db->domains[i]->name, name))
13507ec681f3Smrg			return db->domains[i];
13517ec681f3Smrg	return 0;
13527ec681f3Smrg}
13537ec681f3Smrg
13547ec681f3Smrgstruct rnnspectype *rnn_findspectype (struct rnndb *db, const char *name) {
13557ec681f3Smrg	int i;
13567ec681f3Smrg	for (i = 0; i < db->spectypesnum; i++)
13577ec681f3Smrg		if (!strcmp(db->spectypes[i]->name, name))
13587ec681f3Smrg			return db->spectypes[i];
13597ec681f3Smrg	return 0;
13607ec681f3Smrg}
1361