Home | History | Annotate | Line # | Download | only in rnn
      1 /*
      2  * Copyright (C) 2010-2011 Marcin Kocielnicki <koriakin (at) 0x04.net>
      3  * Copyright (C) 2010 Luca Barbieri <luca (at) luca-barbieri.com>
      4  * Copyright (C) 2010 Francisco Jerez <currojerez (at) riseup.net>
      5  * Copyright (C) 2010 Martin Peres <martin.peres (at) ensi-bourges.fr>
      6  * Copyright (C) 2010 Marcin Slusarz <marcin.slusarz (at) gmail.com>
      7  * All Rights Reserved.
      8  *
      9  * Permission is hereby granted, free of charge, to any person obtaining a
     10  * copy of this software and associated documentation files (the "Software"),
     11  * to deal in the Software without restriction, including without limitation
     12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     13  * and/or sell copies of the Software, and to permit persons to whom the
     14  * Software is furnished to do so, subject to the following conditions:
     15  *
     16  * The above copyright notice and this permission notice (including the next
     17  * paragraph) shall be included in all copies or substantial portions of the
     18  * Software.
     19  *
     20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     24  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     25  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     26  * OTHER DEALINGS IN THE SOFTWARE.
     27  */
     28 
     29 /* workaround libxml2 silliness: */
     30 #pragma GCC diagnostic ignored "-Wpointer-sign"
     31 
     32 #include <libxml/xmlversion.h>
     33 #include <libxml/parser.h>
     34 #include <libxml/xpath.h>
     35 #include <libxml/xmlreader.h>
     36 #include <stdint.h>
     37 #include <string.h>
     38 #include <limits.h>
     39 #include <ctype.h>
     40 #include <stdio.h>
     41 #include "rnn.h"
     42 #include "util.h"
     43 
     44 #include "util/u_debug.h"
     45 
     46 static char *catstr (char *a, char *b) {
     47 	if (!a)
     48 		return b;
     49 	return aprintf("%s_%s", a, b);
     50 }
     51 
     52 static int strdiff (const char *a, const char *b) {
     53 	if (!a && !b)
     54 		return 0;
     55 	if (!a || !b)
     56 		return 1;
     57 	return strcmp (a, b);
     58 }
     59 
     60 static void rnn_err(struct rnndb *db, const char *format, ...) _util_printf_format(2, 3);
     61 
     62 static void rnn_err(struct rnndb *db, const char *format, ...)
     63 {
     64 	va_list ap;
     65 	va_start(ap, format);
     66 	vfprintf(stderr, format, ap);
     67 	va_end(ap);
     68 	db->estatus = 1;
     69 }
     70 
     71 void rnn_init(void) {
     72 	LIBXML_TEST_VERSION
     73 	xmlInitParser();
     74 }
     75 
     76 struct rnndb *rnn_newdb(void) {
     77 	struct rnndb *db = calloc(sizeof *db, 1);
     78 	return db;
     79 }
     80 
     81 static char *getcontent (xmlNode *attr) {
     82 	xmlNode *chain = attr->children;
     83 	size_t size = 0;
     84 	char *content, *p;
     85 	while (chain) {
     86 		if (chain->type == XML_TEXT_NODE)
     87 			size += strlen(chain->content);
     88 		chain = chain->next;
     89 	}
     90 	p = content = malloc(size + 1);
     91 	chain = attr->children;
     92 	while (chain) {
     93 		if (chain->type == XML_TEXT_NODE) {
     94 			char* sp = chain->content;
     95 			if(p == content) {
     96 				while(isspace(*sp))
     97 					++sp;
     98 			}
     99 			size_t len = strlen(sp);
    100 			memcpy(p, sp, len);
    101 			p += len;
    102 		}
    103 		chain = chain->next;
    104 	}
    105 	while(p != content && isspace(p[-1]))
    106 		--p;
    107 	*p = 0;
    108 	return content;
    109 }
    110 
    111 static char *getattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
    112 	xmlNode *chain = attr->children;
    113 	while (chain) {
    114 		if (chain->type != XML_TEXT_NODE) {
    115 			rnn_err(db, "%s:%d: unknown attribute child \"%s\" in attribute \"%s\"\n", file, line, chain->name, attr->name);
    116 		} else {
    117 			return chain->content;
    118 		}
    119 		chain = chain->next;
    120 	}
    121 	return "";
    122 }
    123 
    124 static int getboolattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
    125 	char *c = getattrib(db, file, line, attr);
    126 	if (!strcmp(c, "yes") || !strcmp(c, "1") || !strcmp(c, "true"))
    127 		return 1;
    128 	if (!strcmp(c, "no") || !strcmp(c, "0") || !strcmp(c, "false"))
    129 		return 0;
    130 	rnn_err(db, "%s:%d: invalid boolean value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name);
    131 	return 0;
    132 }
    133 
    134 static uint64_t getnum(struct rnndb *db, char *file, int line, xmlAttr *attr, char *c)
    135 {
    136 	char *cc;
    137 	uint64_t res;
    138 	if (strchr(c, 'x') || strchr(c, 'X'))
    139 		res = strtoull(c, &cc, 16);
    140 	else
    141 		res = strtoull(c, &cc, 10);
    142 	if (*cc)  {
    143 		rnn_err(db, "%s:%d: invalid numeric value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name);
    144 	}
    145 	return res;
    146 }
    147 
    148 static uint64_t getnumattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
    149 	char *c = getattrib(db, file, line, attr);
    150 	return getnum(db, file, line, attr, c);
    151 }
    152 
    153 static int trytop (struct rnndb *db, char *file, xmlNode *node);
    154 
    155 static int trydoc (struct rnndb *db, char *file, xmlNode *node) {
    156 	if (!strcmp(node->name, "brief")) {
    157 		return 1;
    158 	} else if (!strcmp(node->name, "doc")) {
    159 		return 1;
    160 	}
    161 	return 0;
    162 }
    163 
    164 static struct rnnvalue *parsevalue(struct rnndb *db, char *file, xmlNode *node);
    165 static struct rnnbitfield *parsebitfield(struct rnndb *db, char *file, xmlNode *node);
    166 
    167 static int trytypetag (struct rnndb *db, char *file, xmlNode *node, struct rnntypeinfo *ti) {
    168 	if (!strcmp(node->name, "value")) {
    169 		struct rnnvalue *val = parsevalue(db, file, node);
    170 		if (val)
    171 			ADDARRAY(ti->vals, val);
    172 		return 1;
    173 	} else if (!strcmp(node->name, "bitfield")) {
    174 		struct rnnbitfield *bf = parsebitfield(db, file, node);
    175 		if (bf)
    176 			ADDARRAY(ti->bitfields, bf);
    177 		return 1;
    178 	}
    179 	return 0;
    180 }
    181 static int trytypeattr (struct rnndb *db, char *file, xmlNode *node, xmlAttr *attr, struct rnntypeinfo *ti) {
    182 	if (!strcmp(attr->name, "shr")) {
    183 		ti->shr = getnumattrib(db, file, node->line, attr);
    184 		return 1;
    185 	} else if (!strcmp(attr->name, "min")) {
    186 		ti->min = getnumattrib(db, file, node->line, attr);
    187 		ti->minvalid = 1;
    188 		return 1;
    189 	} else if (!strcmp(attr->name, "max")) {
    190 		ti->max = getnumattrib(db, file, node->line, attr);
    191 		ti->maxvalid = 1;
    192 		return 1;
    193 	} else if (!strcmp(attr->name, "align")) {
    194 		ti->align = getnumattrib(db, file, node->line, attr);
    195 		ti->alignvalid = 1;
    196 		return 1;
    197 	} else if (!strcmp(attr->name, "type")) {
    198 		ti->name = strdup(getattrib(db, file, node->line, attr));;
    199 		return 1;
    200 	} else if (!strcmp(attr->name, "radix")) {
    201 		ti->radix = getnumattrib(db, file, node->line, attr);
    202 		ti->radixvalid = 1;
    203 		return 1;
    204 	} else if (!strcmp(attr->name, "pos")) {
    205 		ti->high = ti->low = getnumattrib(db, file, node->line, attr);
    206 		return 1;
    207 	} else if (!strcmp(attr->name, "low")) {
    208 		ti->low = getnumattrib(db, file, node->line, attr);
    209 		return 1;
    210 	} else if (!strcmp(attr->name, "high")) {
    211 		ti->high = getnumattrib(db, file, node->line, attr);
    212 		return 1;
    213 	} else if (!strcmp(attr->name, "addvariant")) {
    214 		ti->addvariant = getboolattrib(db, file, node->line, attr);
    215 		return 1;
    216 	}
    217 	return 0;
    218 }
    219 
    220 static struct rnnvalue *parsevalue(struct rnndb *db, char *file, xmlNode *node) {
    221 	struct rnnvalue *val = calloc(sizeof *val, 1);
    222 	val->file = file;
    223 	xmlAttr *attr = node->properties;
    224 	while (attr) {
    225 		if (!strcmp(attr->name, "name")) {
    226 			val->name = strdup(getattrib(db, file, node->line, attr));
    227 		} else if (!strcmp(attr->name, "value")) {
    228 			val->value = getnumattrib(db, file, node->line, attr);
    229 			val->valvalid = 1;
    230 		} else if (!strcmp(attr->name, "varset")) {
    231 			val->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
    232 		} else if (!strcmp(attr->name, "variants")) {
    233 			val->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
    234 		} else {
    235 			rnn_err(db, "%s:%d: wrong attribute \"%s\" for value\n", file, node->line, attr->name);
    236 		}
    237 		attr = attr->next;
    238 	}
    239 	xmlNode *chain = node->children;
    240 	while (chain) {
    241 		if (chain->type != XML_ELEMENT_NODE) {
    242 		} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
    243 			rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
    244 		}
    245 		chain = chain->next;
    246 	}
    247 	if (!val->name) {
    248 		rnn_err(db, "%s:%d: nameless value\n", file, node->line);
    249 		return 0;
    250 	} else {
    251 		return val;
    252 	}
    253 }
    254 
    255 static void parsespectype(struct rnndb *db, char *file, xmlNode *node) {
    256 	struct rnnspectype *res = calloc (sizeof *res, 1);
    257 	res->file = file;
    258 	xmlAttr *attr = node->properties;
    259 	int i;
    260 	while (attr) {
    261 		if (!strcmp(attr->name, "name")) {
    262 			res->name = strdup(getattrib(db, file, node->line, attr));
    263 		} else if (!trytypeattr(db, file, node, attr, &res->typeinfo)) {
    264 			rnn_err(db, "%s:%d: wrong attribute \"%s\" for spectype\n", file, node->line, attr->name);
    265 		}
    266 		attr = attr->next;
    267 	}
    268 	if (!res->name) {
    269 		rnn_err(db, "%s:%d: nameless spectype\n", file, node->line);
    270 		return;
    271 	}
    272 	for (i = 0; i < db->spectypesnum; i++)
    273 		if (!strcmp(db->spectypes[i]->name, res->name)) {
    274 			rnn_err(db, "%s:%d: duplicated spectype name %s\n", file, node->line, res->name);
    275 			return;
    276 		}
    277 	ADDARRAY(db->spectypes, res);
    278 	xmlNode *chain = node->children;
    279 	while (chain) {
    280 		if (chain->type != XML_ELEMENT_NODE) {
    281 		} else if (!trytypetag(db, file, chain, &res->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) {
    282 			rnn_err(db, "%s:%d: wrong tag in spectype: <%s>\n", file, chain->line, chain->name);
    283 		}
    284 		chain = chain->next;
    285 	}
    286 }
    287 
    288 static void parseenum(struct rnndb *db, char *file, xmlNode *node) {
    289 	xmlAttr *attr = node->properties;
    290 	char *name = 0;
    291 	int isinline = 0;
    292 	int bare = 0;
    293 	char *prefixstr = 0;
    294 	char *varsetstr = 0;
    295 	char *variantsstr = 0;
    296 	int i;
    297 	while (attr) {
    298 		if (!strcmp(attr->name, "name")) {
    299 			name = getattrib(db, file, node->line, attr);
    300 		} else if (!strcmp(attr->name, "bare")) {
    301 			bare = getboolattrib(db, file, node->line, attr);
    302 		} else if (!strcmp(attr->name, "inline")) {
    303 			isinline = getboolattrib(db, file, node->line, attr);
    304 		} else if (!strcmp(attr->name, "prefix")) {
    305 			prefixstr = strdup(getattrib(db, file, node->line, attr));
    306 		} else if (!strcmp(attr->name, "varset")) {
    307 			varsetstr = strdup(getattrib(db, file, node->line, attr));
    308 		} else if (!strcmp(attr->name, "variants")) {
    309 			variantsstr = strdup(getattrib(db, file, node->line, attr));
    310 		} else {
    311 			rnn_err(db, "%s:%d: wrong attribute \"%s\" for enum\n", file, node->line, attr->name);
    312 		}
    313 		attr = attr->next;
    314 	}
    315 	if (!name) {
    316 		rnn_err(db, "%s:%d: nameless enum\n", file, node->line);
    317 		return;
    318 	}
    319 	struct rnnenum *cur = 0;
    320 	for (i = 0; i < db->enumsnum; i++)
    321 		if (!strcmp(db->enums[i]->name, name)) {
    322 			cur = db->enums[i];
    323 			break;
    324 		}
    325 	if (cur) {
    326 		if (strdiff(cur->varinfo.prefixstr, prefixstr) ||
    327 				strdiff(cur->varinfo.varsetstr, varsetstr) ||
    328 				strdiff(cur->varinfo.variantsstr, variantsstr) ||
    329 				cur->isinline != isinline || cur->bare != bare) {
    330 			rnn_err(db, "%s:%d: merge fail for enum %s\n", file, node->line, node->name);
    331 		}
    332 	} else {
    333 		cur = calloc(sizeof *cur, 1);
    334 		cur->name = strdup(name);
    335 		cur->isinline = isinline;
    336 		cur->bare = bare;
    337 		cur->varinfo.prefixstr = prefixstr;
    338 		cur->varinfo.varsetstr = varsetstr;
    339 		cur->varinfo.variantsstr = variantsstr;
    340 		cur->file = file;
    341 		ADDARRAY(db->enums, cur);
    342 	}
    343 	xmlNode *chain = node->children;
    344 	while (chain) {
    345 		if (chain->type != XML_ELEMENT_NODE) {
    346 		} else if (!strcmp(chain->name, "value")) {
    347 			struct rnnvalue *val = parsevalue(db, file, chain);
    348 			if (val)
    349 				ADDARRAY(cur->vals, val);
    350 		} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
    351 			rnn_err(db, "%s:%d: wrong tag in enum: <%s>\n", file, chain->line, chain->name);
    352 		}
    353 		chain = chain->next;
    354 	}
    355 }
    356 
    357 static struct rnnbitfield *parsebitfield(struct rnndb *db, char *file, xmlNode *node) {
    358 	struct rnnbitfield *bf = calloc(sizeof *bf, 1);
    359 	bf->file = file;
    360 	xmlAttr *attr = node->properties;
    361 	bf->typeinfo.low = bf->typeinfo.high = -1;
    362 	while (attr) {
    363 		if (!strcmp(attr->name, "name")) {
    364 			bf->name = strdup(getattrib(db, file, node->line, attr));
    365 		} else if (!strcmp(attr->name, "varset")) {
    366 			bf->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
    367 		} else if (!strcmp(attr->name, "variants")) {
    368 			bf->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
    369 		} else if (!trytypeattr(db, file, node, attr, &bf->typeinfo)) {
    370 			rnn_err(db, "%s:%d: wrong attribute \"%s\" for bitfield\n", file, node->line, attr->name);
    371 		}
    372 		attr = attr->next;
    373 	}
    374 	xmlNode *chain = node->children;
    375 	while (chain) {
    376 		if (chain->type != XML_ELEMENT_NODE) {
    377 		} else if (!trytypetag(db, file, chain, &bf->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) {
    378 			rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
    379 		}
    380 		chain = chain->next;
    381 	}
    382 	if (!bf->name) {
    383 		rnn_err(db, "%s:%d: nameless bitfield\n", file, node->line);
    384 		return 0;
    385 	} else if (bf->typeinfo.low < 0|| bf->typeinfo.high < 0 || bf->typeinfo.high < bf->typeinfo.low) {
    386 		rnn_err(db, "%s:%d: bitfield has wrong placement\n", file, node->line);
    387 		return 0;
    388 	} else {
    389 		return bf;
    390 	}
    391 }
    392 
    393 static void parsebitset(struct rnndb *db, char *file, xmlNode *node) {
    394 	xmlAttr *attr = node->properties;
    395 	char *name = 0;
    396 	int isinline = 0;
    397 	int bare = 0;
    398 	char *prefixstr = 0;
    399 	char *varsetstr = 0;
    400 	char *variantsstr = 0;
    401 	int i;
    402 	while (attr) {
    403 		if (!strcmp(attr->name, "name")) {
    404 			name = getattrib(db, file, node->line, attr);
    405 		} else if (!strcmp(attr->name, "bare")) {
    406 			bare = getboolattrib(db, file, node->line, attr);
    407 		} else if (!strcmp(attr->name, "inline")) {
    408 			isinline = getboolattrib(db, file, node->line, attr);
    409 		} else if (!strcmp(attr->name, "prefix")) {
    410 			prefixstr = strdup(getattrib(db, file, node->line, attr));
    411 		} else if (!strcmp(attr->name, "varset")) {
    412 			varsetstr = strdup(getattrib(db, file, node->line, attr));
    413 		} else if (!strcmp(attr->name, "variants")) {
    414 			variantsstr = strdup(getattrib(db, file, node->line, attr));
    415 		} else {
    416 			rnn_err(db, "%s:%d: wrong attribute \"%s\" for bitset\n", file, node->line, attr->name);
    417 		}
    418 		attr = attr->next;
    419 	}
    420 	if (!name) {
    421 		rnn_err(db, "%s:%d: nameless bitset\n", file, node->line);
    422 		return;
    423 	}
    424 	struct rnnbitset *cur = 0;
    425 	for (i = 0; i < db->bitsetsnum; i++)
    426 		if (!strcmp(db->bitsets[i]->name, name)) {
    427 			cur = db->bitsets[i];
    428 			break;
    429 		}
    430 	if (cur) {
    431 		if (strdiff(cur->varinfo.prefixstr, prefixstr) ||
    432 				strdiff(cur->varinfo.varsetstr, varsetstr) ||
    433 				strdiff(cur->varinfo.variantsstr, variantsstr) ||
    434 				cur->isinline != isinline || cur->bare != bare) {
    435 			rnn_err(db, "%s:%d: merge fail for bitset %s\n", file, node->line, node->name);
    436 		}
    437 	} else {
    438 		cur = calloc(sizeof *cur, 1);
    439 		cur->name = strdup(name);
    440 		cur->isinline = isinline;
    441 		cur->bare = bare;
    442 		cur->varinfo.prefixstr = prefixstr;
    443 		cur->varinfo.varsetstr = varsetstr;
    444 		cur->varinfo.variantsstr = variantsstr;
    445 		cur->file = file;
    446 		ADDARRAY(db->bitsets, cur);
    447 	}
    448 	xmlNode *chain = node->children;
    449 	while (chain) {
    450 		if (chain->type != XML_ELEMENT_NODE) {
    451 		} else if (!strcmp(chain->name, "bitfield")) {
    452 			struct rnnbitfield *bf = parsebitfield(db, file, chain);
    453 			if (bf)
    454 				ADDARRAY(cur->bitfields, bf);
    455 		} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
    456 			rnn_err(db, "%s:%d: wrong tag in bitset: <%s>\n", file, chain->line, chain->name);
    457 		}
    458 		chain = chain->next;
    459 	}
    460 }
    461 
    462 static struct rnndelem *trydelem(struct rnndb *db, char *file, xmlNode *node) {
    463 	if (!strcmp(node->name, "use-group")) {
    464 		struct rnndelem *res = calloc(sizeof *res, 1);
    465 		res->file = file;
    466 		res->type = RNN_ETYPE_USE_GROUP;
    467 		xmlAttr *attr = node->properties;
    468 		while (attr) {
    469 			if (!strcmp(attr->name, "ref")) {
    470 				res->name = strdup(getattrib(db, file, node->line, attr));
    471 			} else {
    472 				rnn_err(db, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name);
    473 			}
    474 			attr = attr->next;
    475 		}
    476 		if (!res->name) {
    477 			rnn_err(db, "%s:%d: nameless use-group\n", file, node->line);
    478 			return 0;
    479 		}
    480 		return res;
    481 	} else if (!strcmp(node->name, "stripe") || !strcmp(node->name, "array")) {
    482 		struct rnndelem *res = calloc(sizeof *res, 1);
    483 		if (!strcmp(node->name, "array"))
    484 			res->name = "";
    485 		res->type = (strcmp(node->name, "stripe")?RNN_ETYPE_ARRAY:RNN_ETYPE_STRIPE);
    486 		res->length = 1;
    487 		res->file = file;
    488 		xmlAttr *attr = node->properties;
    489 		while (attr) {
    490 			if (!strcmp(attr->name, "name")) {
    491 				res->name = strdup(getattrib(db, file, node->line, attr));
    492 			} else if (!strcmp(attr->name, "offset")) {
    493 				res->offset = getnumattrib(db, file, node->line, attr);
    494 			} else if (!strcmp(attr->name, "offsets")) {
    495 				char *str = strdup(getattrib(db, file, node->line, attr));
    496 				char *tok, *save, *tmp = str;
    497 				while ((tok = strtok_r(str, ",", &save))) {
    498 					uint64_t offset = getnum(db, file, node->line, attr, tok);
    499 					ADDARRAY(res->offsets, offset);
    500 					str = NULL;
    501 				}
    502 				if (str)
    503 					fprintf(stderr, "%s:%d: invalid offsets: %s\n", file, node->line, str);
    504 				free(tmp);
    505 			} else if (!strcmp(attr->name, "doffset")) {
    506 				/* dynamic runtime determined offset: */
    507 				res->doffset = strdup(getattrib(db, file, node->line, attr));
    508 			} else if (!strcmp(attr->name, "doffsets")) {
    509 				/* dynamic runtime determined offsets: */
    510 				char *str = strdup(getattrib(db, file, node->line, attr));
    511 				char *tok, *save, *tmp = str;
    512 				while ((tok = strtok_r(str, ",", &save))) {
    513 					char *doffset = strdup(tok);
    514 					ADDARRAY(res->doffsets, doffset);
    515 					str = NULL;
    516 				}
    517 				if (str)
    518 					fprintf(stderr, "%s:%d: invalid offsets: %s\n", file, node->line, str);
    519 				free(tmp);
    520 			} else if (!strcmp(attr->name, "length")) {
    521 				res->length = getnumattrib(db, file, node->line, attr);
    522 			} else if (!strcmp(attr->name, "stride")) {
    523 				res->stride = getnumattrib(db, file, node->line, attr);
    524 			} else if (!strcmp(attr->name, "prefix")) {
    525 				res->varinfo.prefixstr = strdup(getattrib(db, file, node->line, attr));
    526 			} else if (!strcmp(attr->name, "varset")) {
    527 				res->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
    528 			} else if (!strcmp(attr->name, "variants")) {
    529 				res->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
    530 			} else if (!strcmp(attr->name, "index")) {
    531 				const char *enumname = getattrib(db, file, node->line, attr);
    532 				res->index = rnn_findenum(db, enumname);
    533 				if (!res->index) {
    534 					rnn_err(db, "%s:%d: invalid enum name \"%s\"\n", file, node->line, enumname);
    535 				}
    536 			} else {
    537 				rnn_err(db, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name);
    538 			}
    539 			attr = attr->next;
    540 		}
    541 		xmlNode *chain = node->children;
    542 		while (chain) {
    543 			struct rnndelem *delem;
    544 			if (chain->type != XML_ELEMENT_NODE) {
    545 			} else if ((delem = trydelem(db, file, chain))) {
    546 				ADDARRAY(res->subelems, delem);
    547 			} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
    548 				rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
    549 			}
    550 			chain = chain->next;
    551 		}
    552 
    553 		/* Sanity checking */
    554 		if (res->type == RNN_ETYPE_ARRAY && res->stride == 0) {
    555 			fprintf(stderr, "%s: Array %s's stride is undefined. Aborting.\n", file, res->name);
    556 			exit(-1);
    557 		}
    558 		return res;
    559 
    560 	}
    561 	int width;
    562 	if (!strcmp(node->name, "reg8"))
    563 		width = 8;
    564 	else if (!strcmp(node->name, "reg16"))
    565 		width = 16;
    566 	else if (!strcmp(node->name, "reg32"))
    567 		width = 32;
    568 	else if (!strcmp(node->name, "reg64"))
    569 		width = 64;
    570 	else
    571 		return 0;
    572 	struct rnndelem *res = calloc(sizeof *res, 1);
    573 	res->file = file;
    574 	res->type = RNN_ETYPE_REG;
    575 	res->width = width;
    576 	res->length = 1;
    577 	res->access = RNN_ACCESS_RW;
    578 	xmlAttr *attr = node->properties;
    579 	res->typeinfo.low = 0;
    580 	res->typeinfo.high = width - 1;
    581 	while (attr) {
    582 		if (!strcmp(attr->name, "name")) {
    583 			res->name = strdup(getattrib(db, file, node->line, attr));
    584 		} else if (!strcmp(attr->name, "offset")) {
    585 			res->offset = getnumattrib(db, file, node->line, attr);
    586 		} else if (!strcmp(attr->name, "length")) {
    587 			res->length = getnumattrib(db, file, node->line, attr);
    588 		} else if (!strcmp(attr->name, "stride")) {
    589 			res->stride = getnumattrib(db, file, node->line, attr);
    590 		} else if (!strcmp(attr->name, "varset")) {
    591 			res->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
    592 		} else if (!strcmp(attr->name, "variants")) {
    593 			res->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
    594 		} else if (!strcmp(attr->name, "access")) {
    595 			char *str = getattrib(db, file, node->line, attr);
    596 			if (!strcmp(str, "r"))
    597 				res->access = RNN_ACCESS_R;
    598 			else if (!strcmp(str, "w"))
    599 				res->access = RNN_ACCESS_W;
    600 			else if (!strcmp(str, "rw"))
    601 				res->access = RNN_ACCESS_RW;
    602 			else
    603 				fprintf (stderr, "%s:%d: wrong access type \"%s\" for register\n", file, node->line, str);
    604 		} else if (!trytypeattr(db, file, node, attr, &res->typeinfo)) {
    605 			rnn_err(db, "%s:%d: wrong attribute \"%s\" for register\n", file, node->line, attr->name);
    606 		}
    607 		attr = attr->next;
    608 	}
    609 	xmlNode *chain = node->children;
    610 	while (chain) {
    611 		if (chain->type != XML_ELEMENT_NODE) {
    612 		} else if (!trytypetag(db, file, chain, &res->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) {
    613 			rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
    614 		}
    615 		chain = chain->next;
    616 	}
    617 	if (!res->name) {
    618 		rnn_err(db, "%s:%d: nameless register\n", file, node->line);
    619 		return 0;
    620 	} else {
    621 	}
    622 	return res;
    623 }
    624 
    625 static void parsegroup(struct rnndb *db, char *file, xmlNode *node) {
    626 	xmlAttr *attr = node->properties;
    627 	char *name = 0;
    628 	int i;
    629 	while (attr) {
    630 		if (!strcmp(attr->name, "name")) {
    631 			name = getattrib(db, file, node->line, attr);
    632 		} else {
    633 			rnn_err(db, "%s:%d: wrong attribute \"%s\" for group\n", file, node->line, attr->name);
    634 		}
    635 		attr = attr->next;
    636 	}
    637 	if (!name) {
    638 		rnn_err(db, "%s:%d: nameless group\n", file, node->line);
    639 		return;
    640 	}
    641 	struct rnngroup *cur = 0;
    642 	for (i = 0; i < db->groupsnum; i++)
    643 		if (!strcmp(db->groups[i]->name, name)) {
    644 			cur = db->groups[i];
    645 			break;
    646 		}
    647 	if (!cur) {
    648 		cur = calloc(sizeof *cur, 1);
    649 		cur->name = strdup(name);
    650 		ADDARRAY(db->groups, cur);
    651 	}
    652 	xmlNode *chain = node->children;
    653 	while (chain) {
    654 		struct rnndelem *delem;
    655 		if (chain->type != XML_ELEMENT_NODE) {
    656 		} else if ((delem = trydelem(db, file, chain))) {
    657 			ADDARRAY(cur->subelems, delem);
    658 		} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
    659 			rnn_err(db, "%s:%d: wrong tag in group: <%s>\n", file, chain->line, chain->name);
    660 		}
    661 		chain = chain->next;
    662 	}
    663 }
    664 
    665 static void parsedomain(struct rnndb *db, char *file, xmlNode *node) {
    666 	xmlAttr *attr = node->properties;
    667 	char *name = 0;
    668 	uint64_t size = 0; int width = 8;
    669 	int bare = 0;
    670 	char *prefixstr = 0;
    671 	char *varsetstr = 0;
    672 	char *variantsstr = 0;
    673 	int i;
    674 	while (attr) {
    675 		if (!strcmp(attr->name, "name")) {
    676 			name = getattrib(db, file, node->line, attr);
    677 		} else if (!strcmp(attr->name, "bare")) {
    678 			bare = getboolattrib(db, file, node->line, attr);
    679 		} else if (!strcmp(attr->name, "size")) {
    680 			size = getnumattrib(db, file, node->line, attr);
    681 		} else if (!strcmp(attr->name, "width")) {
    682 			width = getnumattrib(db, file, node->line, attr);
    683 		} else if (!strcmp(attr->name, "prefix")) {
    684 			prefixstr = strdup(getattrib(db, file, node->line, attr));
    685 		} else if (!strcmp(attr->name, "varset")) {
    686 			varsetstr = strdup(getattrib(db, file, node->line, attr));
    687 		} else if (!strcmp(attr->name, "variants")) {
    688 			variantsstr = strdup(getattrib(db, file, node->line, attr));
    689 		} else {
    690 			rnn_err(db, "%s:%d: wrong attribute \"%s\" for domain\n", file, node->line, attr->name);
    691 		}
    692 		attr = attr->next;
    693 	}
    694 	if (!name) {
    695 		rnn_err(db, "%s:%d: nameless domain\n", file, node->line);
    696 		return;
    697 	}
    698 	struct rnndomain *cur = 0;
    699 	for (i = 0; i < db->domainsnum; i++)
    700 		if (!strcmp(db->domains[i]->name, name)) {
    701 			cur = db->domains[i];
    702 			break;
    703 		}
    704 	if (cur) {
    705 		if (strdiff(cur->varinfo.prefixstr, prefixstr) ||
    706 				strdiff(cur->varinfo.varsetstr, varsetstr) ||
    707 				strdiff(cur->varinfo.variantsstr, variantsstr) ||
    708 				cur->width != width ||
    709 				cur->bare != bare ||
    710 				(size && cur->size && size != cur->size)) {
    711 			rnn_err(db, "%s:%d: merge fail for domain %s\n", file, node->line, node->name);
    712 		} else {
    713 			if (size)
    714 				cur->size = size;
    715 		}
    716 	} else {
    717 		cur = calloc(sizeof *cur, 1);
    718 		cur->name = strdup(name);
    719 		cur->bare = bare;
    720 		cur->width = width;
    721 		cur->size = size;
    722 		cur->varinfo.prefixstr = prefixstr;
    723 		cur->varinfo.varsetstr = varsetstr;
    724 		cur->varinfo.variantsstr = variantsstr;
    725 		cur->file = file;
    726 		ADDARRAY(db->domains, cur);
    727 	}
    728 	xmlNode *chain = node->children;
    729 	while (chain) {
    730 		struct rnndelem *delem;
    731 		if (chain->type != XML_ELEMENT_NODE) {
    732 		} else if ((delem = trydelem(db, file, chain))) {
    733 			ADDARRAY(cur->subelems, delem);
    734 		} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
    735 			rnn_err(db, "%s:%d: wrong tag in domain: <%s>\n", file, chain->line, chain->name);
    736 		}
    737 		chain = chain->next;
    738 	}
    739 }
    740 
    741 static void parsecopyright(struct rnndb *db, char *file, xmlNode *node) {
    742 	struct rnncopyright* copyright = &db->copyright;
    743 	xmlAttr *attr = node->properties;
    744 	while (attr) {
    745 		if (!strcmp(attr->name, "year")) {
    746 			unsigned firstyear = getnumattrib(db, file, node->line, attr);
    747 			if(!copyright->firstyear || firstyear < copyright->firstyear)
    748 				copyright->firstyear = firstyear;
    749 		} else {
    750 			rnn_err(db, "%s:%d: wrong attribute \"%s\" for copyright\n", file, node->line, attr->name);
    751 		}
    752 		attr = attr->next;
    753 	}
    754 	xmlNode *chain = node->children;
    755 	while (chain) {
    756 		if (chain->type != XML_ELEMENT_NODE) {
    757 		} else if (!strcmp(chain->name, "license"))
    758 			if(copyright->license) {
    759 				if(strcmp(copyright->license, node->content)) {
    760 					fprintf(stderr, "fatal error: multiple different licenses specified!\n");
    761 					abort(); /* TODO: do something better here, but headergen, xml2html, etc. should not produce anything in this case */
    762 				}
    763 			} else
    764 				copyright->license = getcontent(chain);
    765 		else if (!strcmp(chain->name, "author")) {
    766 			struct rnnauthor* author = calloc(sizeof *author, 1);
    767 			xmlAttr* authorattr = chain->properties;
    768 			xmlNode *authorchild = chain->children;
    769 			author->contributions = getcontent(chain);
    770 			while (authorattr) {
    771 				if (!strcmp(authorattr->name, "name"))
    772 					author->name = strdup(getattrib(db, file, chain->line, authorattr));
    773 				else if (!strcmp(authorattr->name, "email"))
    774 					author->email = strdup(getattrib(db, file, chain->line, authorattr));
    775 				else {
    776 					rnn_err(db, "%s:%d: wrong attribute \"%s\" for author\n", file, chain->line, authorattr->name);
    777 				}
    778 				authorattr = authorattr->next;
    779 			}
    780 			while(authorchild)  {
    781 				if (authorchild->type != XML_ELEMENT_NODE) {
    782 				} else if (!strcmp(authorchild->name, "nick")) {
    783 					xmlAttr* nickattr = authorchild->properties;
    784 					char* nickname = 0;
    785 					while(nickattr) {
    786 						if (!strcmp(nickattr->name, "name"))
    787 							nickname = strdup(getattrib(db, file, authorchild->line, nickattr));
    788 						else {
    789 							rnn_err(db, "%s:%d: wrong attribute \"%s\" for nick\n", file, authorchild->line, nickattr->name);
    790 						}
    791 						nickattr = nickattr->next;
    792 					}
    793 					if(!nickname) {
    794 						rnn_err(db, "%s:%d: missing \"name\" attribute for nick\n", file, authorchild->line);
    795 					} else
    796 						ADDARRAY(author->nicknames, nickname);
    797 				} else {
    798 					rnn_err(db, "%s:%d: wrong tag in author: <%s>\n", file, authorchild->line, authorchild->name);
    799 				}
    800 				authorchild = authorchild->next;
    801 			}
    802 			ADDARRAY(copyright->authors, author);
    803 		} else {
    804 			rnn_err(db, "%s:%d: wrong tag in copyright: <%s>\n", file, chain->line, chain->name);
    805 		}
    806 		chain = chain->next;
    807 	}
    808 }
    809 
    810 static int trytop (struct rnndb *db, char *file, xmlNode *node) {
    811 	if (!strcmp(node->name, "enum")) {
    812 		parseenum(db, file, node);
    813 		return 1;
    814 	} else if (!strcmp(node->name, "bitset")) {
    815 		parsebitset(db, file, node);
    816 		return 1;
    817 	} else if (!strcmp(node->name, "group")) {
    818 		parsegroup(db, file, node);
    819 		return 1;
    820 	} else if (!strcmp(node->name, "domain")) {
    821 		parsedomain(db, file, node);
    822 		return 1;
    823 	} else if (!strcmp(node->name, "spectype")) {
    824 		parsespectype(db, file, node);
    825 		return 1;
    826 	} else if (!strcmp(node->name, "import")) {
    827 		xmlAttr *attr = node->properties;
    828 		char *subfile = 0;
    829 		while (attr) {
    830 			if (!strcmp(attr->name, "file")) {
    831 				subfile = getattrib(db, file, node->line, attr);
    832 			} else {
    833 				rnn_err(db, "%s:%d: wrong attribute \"%s\" for import\n", file, node->line, attr->name);
    834 			}
    835 			attr = attr->next;
    836 		}
    837 		if (!subfile) {
    838 			rnn_err(db, "%s:%d: missing \"file\" attribute for import\n", file, node->line);
    839 		} else {
    840 			rnn_parsefile(db, subfile);
    841 		}
    842 		return 1;
    843 	} else if (!strcmp(node->name, "copyright")) {
    844 		parsecopyright(db, file, node);
    845 		return 1;
    846 	}
    847 	return 0;
    848 }
    849 
    850 static char * find_file(const char *file_orig)
    851 {
    852 	const char *rnn_path = getenv("RNN_PATH");
    853 	char *fname;
    854 
    855 	if (!rnn_path)
    856 		rnn_path = RNN_DEF_PATH;
    857 
    858 	FILE *file = find_in_path(file_orig, rnn_path, &fname);
    859 	if (!file) {
    860 		fprintf (stderr, "%s: couldn't find database file. Please set the env var RNN_PATH.\n", file_orig);
    861 		return NULL;
    862 	}
    863 	fclose(file);
    864 
    865 	return fname;
    866 }
    867 
    868 static int validate_doc(struct rnndb *db, xmlDocPtr doc, xmlNodePtr database)
    869 {
    870 	/* find the schemaLocation property: */
    871 	xmlAttrPtr attr = database->properties;
    872 	const char *schema_name = NULL;
    873 	char *schema_path;
    874 
    875 	while (attr) {
    876 		if (!strcmp(attr->name, "schemaLocation")) {
    877 			xmlNodePtr data = attr->children;
    878 			schema_name = data->content;
    879 			/* we expect this to look like <namespace url> schema.xsd.. I think
    880 			 * technically it is supposed to be just a URL, but that doesn't
    881 			 * quite match up to what we do.. Just skip over everything up to
    882 			 * and including the first whitespace character:
    883 			 */
    884 			while (schema_name && (schema_name[0] != ' '))
    885 				schema_name++;
    886 			schema_name++;
    887 			break;
    888 		}
    889 	}
    890 
    891 	if (!schema_name) {
    892 		rnn_err(db, "could not find schema.  Missing schemaLocation?");
    893 		return 0;
    894 	}
    895 
    896 	schema_path = find_file(schema_name);
    897 	if (!schema_path) {
    898 		rnn_err(db, "%s: couldn't find database file. Please set the env var RNN_PATH.\n", schema_name);
    899 		return 0;
    900 	}
    901 
    902 	xmlSchemaParserCtxtPtr parser = xmlSchemaNewParserCtxt(schema_path);
    903 	xmlSchemaPtr schema = xmlSchemaParse(parser);
    904 	xmlSchemaValidCtxtPtr validCtxt = xmlSchemaNewValidCtxt(schema);
    905 	int ret = xmlSchemaValidateDoc(validCtxt, doc);
    906 
    907 	xmlSchemaFreeValidCtxt(validCtxt);
    908 	xmlSchemaFree(schema);
    909 	xmlSchemaFreeParserCtxt(parser);
    910 
    911 	free(schema_path);
    912 
    913 	return ret;
    914 }
    915 
    916 void rnn_parsefile (struct rnndb *db, char *file_orig) {
    917 	int i;
    918 	char *fname;
    919 
    920 	fname = find_file(file_orig);
    921 	if (!fname) {
    922 		db->estatus = 1;
    923 		return;
    924 	}
    925 
    926 	for (i = 0; i < db->filesnum; i++)
    927 		if (!strcmp(db->files[i], fname))
    928 			return;
    929 
    930 	ADDARRAY(db->files, fname);
    931 	xmlDocPtr doc = xmlParseFile(fname);
    932 	if (!doc) {
    933 		rnn_err(db, "%s: couldn't open database file. Please set the env var RNN_PATH.\n", fname);
    934 		return;
    935 	}
    936 	xmlNode *root = doc->children;
    937 	while (root) {
    938 		if (root->type != XML_ELEMENT_NODE) {
    939 		} else if (strcmp(root->name, "database")) {
    940 			rnn_err(db, "%s:%d: wrong top-level tag <%s>\n", fname, root->line, root->name);
    941 		} else {
    942 			xmlNode *chain = root->children;
    943 			if (validate_doc(db, doc, root)) {
    944 				rnn_err(db, "%s: database file has errors\n", fname);
    945 				return;
    946 			}
    947 			while (chain) {
    948 				if (chain->type != XML_ELEMENT_NODE) {
    949 				} else if (!trytop(db, fname, chain) && !trydoc(db, fname, chain)) {
    950 					rnn_err(db, "%s:%d: wrong tag in database: <%s>\n", fname, chain->line, chain->name);
    951 				}
    952 				chain = chain->next;
    953 			}
    954 		}
    955 		root = root->next;
    956 	}
    957 	xmlFreeDoc(doc);
    958 }
    959 
    960 static struct rnnvalue *copyvalue (struct rnnvalue *val, char *file) {
    961 	struct rnnvalue *res = calloc (sizeof *res, 1);
    962 	res->name = val->name;
    963 	res->valvalid = val->valvalid;
    964 	res->value = val->value;
    965 	res->varinfo = val->varinfo;
    966 	res->file = file;
    967 	return res;
    968 }
    969 
    970 static struct rnnbitfield *copybitfield (struct rnnbitfield *bf, char *file);
    971 
    972 
    973 static void copytypeinfo (struct rnntypeinfo *dst, struct rnntypeinfo *src, char *file) {
    974 	int i;
    975 	dst->name = src->name;
    976 	dst->shr = src->shr;
    977 	dst->low = src->low;
    978 	dst->high = src->high;
    979 	dst->min = src->min;
    980 	dst->max = src->max;
    981 	dst->align = src->align;
    982 	dst->addvariant = src->addvariant;
    983 	for (i = 0; i < src->valsnum; i++)
    984 		ADDARRAY(dst->vals, copyvalue(src->vals[i], file));
    985 	for (i = 0; i < src->bitfieldsnum; i++)
    986 		ADDARRAY(dst->bitfields, copybitfield(src->bitfields[i], file));
    987 }
    988 
    989 static struct rnnbitfield *copybitfield (struct rnnbitfield *bf, char *file) {
    990 	struct rnnbitfield *res = calloc (sizeof *res, 1);
    991 	res->name = bf->name;
    992 	res->varinfo = bf->varinfo;
    993 	res->file = file;
    994 	copytypeinfo(&res->typeinfo, &bf->typeinfo, file);
    995 	return res;
    996 }
    997 
    998 static struct rnndelem *copydelem (struct rnndelem *elem, char *file) {
    999 	struct rnndelem *res = calloc (sizeof *res, 1);
   1000 	res->type = elem->type;
   1001 	res->name = elem->name;
   1002 	res->width = elem->width;
   1003 	res->access = elem->access;
   1004 	res->offset = elem->offset;
   1005 	res->length = elem->length;
   1006 	res->stride = elem->stride;
   1007 	res->varinfo = elem->varinfo;
   1008 	res->file = file;
   1009 	copytypeinfo(&res->typeinfo, &elem->typeinfo, file);
   1010 	int i;
   1011 	for (i = 0; i < elem->subelemsnum; i++)
   1012 		ADDARRAY(res->subelems, copydelem(elem->subelems[i], file));
   1013 	for (i = 0; i < elem->offsetsnum; i++)
   1014 		ADDARRAY(res->offsets, elem->offsets[i]);
   1015 	return res;
   1016 }
   1017 
   1018 static struct rnnvarset *copyvarset (struct rnnvarset *varset) {
   1019 	struct rnnvarset *res = calloc(sizeof *res, 1);
   1020 	res->venum = varset->venum;
   1021 	res->variants = calloc(sizeof *res->variants, res->venum->valsnum);
   1022 	int i;
   1023 	for (i = 0; i < res->venum->valsnum; i++)
   1024 		res->variants[i] = varset->variants[i];
   1025 	return res;
   1026 }
   1027 
   1028 static void prepenum(struct rnndb *db, struct rnnenum *en);
   1029 
   1030 static int findvidx (struct rnndb *db, struct rnnenum *en, char *name) {
   1031 	int i;
   1032 	for (i = 0; i < en->valsnum; i++)
   1033 		if (!strcmp(en->vals[i]->name, name))
   1034 			return i;
   1035 	rnn_err(db, "Cannot find variant %s in enum %s!\n", name, en->name);
   1036 	return -1;
   1037 }
   1038 
   1039 static void prepvarinfo (struct rnndb *db, char *what, struct rnnvarinfo *vi, struct rnnvarinfo *parent) {
   1040 	if (parent)
   1041 		vi->prefenum = parent->prefenum;
   1042 	if (vi->prefixstr) {
   1043 		if (!strcmp(vi->prefixstr, "none"))
   1044 			vi->prefenum = 0;
   1045 		else
   1046 			vi->prefenum = rnn_findenum(db, vi->prefixstr); // XXX
   1047 	}
   1048 	int i;
   1049 	if (parent)
   1050 		for (i = 0; i < parent->varsetsnum; i++)
   1051 			ADDARRAY(vi->varsets, copyvarset(parent->varsets[i]));
   1052 	struct rnnenum *varset = vi->prefenum;
   1053 	if (!varset && !vi->varsetstr && parent)
   1054 		vi->varsetstr = parent->varsetstr;
   1055 	if (vi->varsetstr)
   1056 		varset = rnn_findenum(db, vi->varsetstr);
   1057 	if (vi->variantsstr) {
   1058 		char *vars = vi->variantsstr;
   1059 		if (!varset) {
   1060 			rnn_err(db, "%s: tried to use variants without active varset!\n", what);
   1061 			return;
   1062 		}
   1063 		struct rnnvarset *vs = 0;
   1064 		int nvars = varset->valsnum;
   1065 		for (i = 0; i < vi->varsetsnum; i++)
   1066 			if (vi->varsets[i]->venum == varset) {
   1067 				vs = vi->varsets[i];
   1068 				break;
   1069 			}
   1070 		if (!vs) {
   1071 			vs = calloc (sizeof *vs, 1);
   1072 			vs->venum = varset;
   1073 			vs->variants = calloc(sizeof *vs->variants, nvars);
   1074 			for (i = 0; i < nvars; i++)
   1075 				vs->variants[i] = 1;
   1076 			ADDARRAY(vi->varsets, vs);
   1077 		}
   1078 		while (1) {
   1079 			while (*vars == ' ') vars++;
   1080 			if (*vars == 0)
   1081 				break;
   1082 			char *split = vars;
   1083 			while (*split != ':' && *split != '-' && *split != ' '  && *split != 0)
   1084 				split++;
   1085 			char *first = 0;
   1086 			if (split != vars)
   1087 				first = strndup(vars, split-vars);
   1088 			if (*split == ' ' || *split == 0) {
   1089 				int idx = findvidx(db, varset, first);
   1090 				if (idx != -1)
   1091 					vs->variants[idx] |= 2;
   1092 				vars = split;
   1093 			} else {
   1094 				char *end = split+1;
   1095 				while (*end != ' '  && *end != 0)
   1096 					end++;
   1097 				char *second = 0;
   1098 				if (end != split+1)
   1099 					second = strndup(split+1, end-split-1);
   1100 				int idx1 = 0;
   1101 				if (first)
   1102 					idx1 = findvidx(db, varset, first);
   1103 				int idx2 = nvars;
   1104 				if (second) {
   1105 					idx2 = findvidx(db, varset, second);
   1106 					if (*split == '-')
   1107 						idx2++;
   1108 				}
   1109 				if (idx1 != -1 && idx2 != -1)
   1110 					for (i = idx1; i < idx2; i++)
   1111 						vs->variants[i] |= 2;
   1112 				vars = end;
   1113 				free(second);
   1114 			}
   1115 			free(first);
   1116 		}
   1117 		vi->dead = 1;
   1118 		for (i = 0; i < nvars; i++) {
   1119 			vs->variants[i] = (vs->variants[i] == 3);
   1120 			if (vs->variants[i])
   1121 				vi->dead = 0;
   1122 		}
   1123 	}
   1124 	if (vi->dead)
   1125 		return;
   1126 	if (vi->prefenum) {
   1127 		struct rnnvarset *vs = 0;
   1128 		for (i = 0; i < vi->varsetsnum; i++)
   1129 			if (vi->varsets[i]->venum == vi->prefenum) {
   1130 				vs = vi->varsets[i];
   1131 				break;
   1132 			}
   1133 		if (vs) {
   1134 			for (i = 0; i < vi->prefenum->valsnum; i++)
   1135 				if (vs->variants[i]) {
   1136 					vi->prefix = vi->prefenum->vals[i]->name;
   1137 					return;
   1138 				}
   1139 		} else {
   1140 			vi->prefix = vi->prefenum->vals[0]->name;
   1141 		}
   1142 	}
   1143 }
   1144 
   1145 static void prepvalue(struct rnndb *db, struct rnnvalue *val, char *prefix, struct rnnvarinfo *parvi) {
   1146 	val->fullname = catstr(prefix, val->name);
   1147 	prepvarinfo (db, val->fullname, &val->varinfo, parvi);
   1148 	if (val->varinfo.dead)
   1149 		return;
   1150 	if (val->varinfo.prefix)
   1151 		val->fullname = catstr(val->varinfo.prefix, val->fullname);
   1152 }
   1153 
   1154 static void prepbitfield(struct rnndb *db, struct rnnbitfield *bf, char *prefix, struct rnnvarinfo *parvi);
   1155 
   1156 static void preptypeinfo(struct rnndb *db, struct rnntypeinfo *ti, char *prefix, struct rnnvarinfo *vi, char *file) {
   1157 	int i;
   1158 	if (ti->name) {
   1159 		struct rnnenum *en = rnn_findenum (db, ti->name);
   1160 		struct rnnbitset *bs = rnn_findbitset (db, ti->name);
   1161 		struct rnnspectype *st = rnn_findspectype (db, ti->name);
   1162 		if (en) {
   1163 			if (en->isinline) {
   1164 				ti->type = RNN_TTYPE_INLINE_ENUM;
   1165 				int j;
   1166 				for (j = 0; j < en->valsnum; j++)
   1167 					ADDARRAY(ti->vals, copyvalue(en->vals[j], file));
   1168 			} else {
   1169 				ti->type = RNN_TTYPE_ENUM;
   1170 				ti->eenum = en;
   1171 			}
   1172 		} else if (bs) {
   1173 			if (bs->isinline) {
   1174 				ti->type = RNN_TTYPE_INLINE_BITSET;
   1175 				int j;
   1176 				for (j = 0; j < bs->bitfieldsnum; j++)
   1177 					ADDARRAY(ti->bitfields, copybitfield(bs->bitfields[j], file));
   1178 			} else {
   1179 				ti->type = RNN_TTYPE_BITSET;
   1180 				ti->ebitset = bs;
   1181 			}
   1182 		} else if (st) {
   1183 			ti->type = RNN_TTYPE_SPECTYPE;
   1184 			ti->spectype = st;
   1185 		} else if (!strcmp(ti->name, "hex")) {
   1186 			ti->type = RNN_TTYPE_HEX;
   1187 		} else if (!strcmp(ti->name, "float")) {
   1188 			ti->type = RNN_TTYPE_FLOAT;
   1189 		} else if (!strcmp(ti->name, "uint")) {
   1190 			ti->type = RNN_TTYPE_UINT;
   1191 		} else if (!strcmp(ti->name, "int")) {
   1192 			ti->type = RNN_TTYPE_INT;
   1193 		} else if (!strcmp(ti->name, "boolean")) {
   1194 			ti->type = RNN_TTYPE_BOOLEAN;
   1195 		} else if (!strcmp(ti->name, "bitfield")) {
   1196 			ti->type = RNN_TTYPE_INLINE_BITSET;
   1197 		} else if (!strcmp(ti->name, "enum")) {
   1198 			ti->type = RNN_TTYPE_INLINE_ENUM;
   1199 		} else if (!strcmp(ti->name, "fixed")) {
   1200 			ti->type = RNN_TTYPE_FIXED;
   1201 		} else if (!strcmp(ti->name, "ufixed")) {
   1202 			ti->type = RNN_TTYPE_UFIXED;
   1203 		} else if (!strcmp(ti->name, "a3xx_regid")) {
   1204 			ti->type = RNN_TTYPE_A3XX_REGID;
   1205 		} else if (!strcmp(ti->name, "waddress") || !strcmp(ti->name, "address")) {
   1206 			ti->type = RNN_TTYPE_HEX;
   1207 		} else {
   1208 			ti->type = RNN_TTYPE_HEX;
   1209 			rnn_err(db, "%s: unknown type %s\n", prefix, ti->name);
   1210 		}
   1211 	} else if (ti->bitfieldsnum) {
   1212 		ti->name = "bitfield";
   1213 		ti->type = RNN_TTYPE_INLINE_BITSET;
   1214 	} else if (ti->valsnum) {
   1215 		ti->name = "enum";
   1216 		ti->type = RNN_TTYPE_INLINE_ENUM;
   1217 	} else if (ti->low == 0 && ti->high == 0) {
   1218 		ti->name = "boolean";
   1219 		ti->type = RNN_TTYPE_BOOLEAN;
   1220 	} else {
   1221 		ti->name = "hex";
   1222 		ti->type = RNN_TTYPE_HEX;
   1223 	}
   1224 	if (ti->addvariant && ti->type != RNN_TTYPE_ENUM) {
   1225 		rnn_err(db, "%s: addvariant specified on non-enum type %s\n", prefix, ti->name);
   1226 	}
   1227 	for (i = 0; i < ti->bitfieldsnum; i++)
   1228 		prepbitfield(db,  ti->bitfields[i], prefix, vi);
   1229 	for (i = 0; i < ti->valsnum; i++)
   1230 		prepvalue(db, ti->vals[i], prefix, vi);
   1231 }
   1232 
   1233 static void prepbitfield(struct rnndb *db, struct rnnbitfield *bf, char *prefix, struct rnnvarinfo *parvi) {
   1234 	bf->fullname = catstr(prefix, bf->name);
   1235 	prepvarinfo (db, bf->fullname, &bf->varinfo, parvi);
   1236 	if (bf->varinfo.dead)
   1237 		return;
   1238 	preptypeinfo(db, &bf->typeinfo, bf->fullname, &bf->varinfo, bf->file);
   1239 	if (bf->varinfo.prefix)
   1240 		bf->fullname = catstr(bf->varinfo.prefix, bf->fullname);
   1241 }
   1242 
   1243 static void prepdelem(struct rnndb *db, struct rnndelem *elem, char *prefix, struct rnnvarinfo *parvi, int width) {
   1244 	if (elem->type == RNN_ETYPE_USE_GROUP) {
   1245 		int i;
   1246 		struct rnngroup *gr = 0;
   1247 		for (i = 0; i < db->groupsnum; i++)
   1248 			if (!strcmp(db->groups[i]->name, elem->name)) {
   1249 				gr = db->groups[i];
   1250 				break;
   1251 			}
   1252 		if (gr) {
   1253 			for (i = 0; i < gr->subelemsnum; i++)
   1254 				ADDARRAY(elem->subelems, copydelem(gr->subelems[i], elem->file));
   1255 		} else {
   1256 			rnn_err(db, "group %s not found!\n", elem->name);
   1257 		}
   1258 		elem->type = RNN_ETYPE_STRIPE;
   1259 		elem->length = 1;
   1260 		elem->name = 0;
   1261 	}
   1262 	if (elem->name)
   1263 		elem->fullname = catstr(prefix, elem->name);
   1264 	prepvarinfo (db, elem->fullname?elem->fullname:prefix, &elem->varinfo, parvi);
   1265 	if (elem->varinfo.dead)
   1266 		return;
   1267 	if (elem->length != 1 && !elem->stride) {
   1268 		if (elem->type != RNN_ETYPE_REG) {
   1269 			rnn_err(db, "%s has non-1 length, but no stride!\n", elem->fullname);
   1270 		} else {
   1271 			elem->stride = elem->width/width;
   1272 		}
   1273 	}
   1274 	preptypeinfo(db, &elem->typeinfo, elem->name?elem->fullname:prefix, &elem->varinfo, elem->file);
   1275 
   1276 	int i;
   1277 	for (i = 0; i < elem->subelemsnum; i++)
   1278 		prepdelem(db,  elem->subelems[i], elem->name?elem->fullname:prefix, &elem->varinfo, width);
   1279 	if (elem->varinfo.prefix && elem->name)
   1280 		elem->fullname = catstr(elem->varinfo.prefix, elem->fullname);
   1281 }
   1282 
   1283 static void prepdomain(struct rnndb *db, struct rnndomain *dom) {
   1284 	prepvarinfo (db, dom->name, &dom->varinfo, 0);
   1285 	int i;
   1286 	for (i = 0; i < dom->subelemsnum; i++)
   1287 		prepdelem(db, dom->subelems[i], dom->bare?0:dom->name, &dom->varinfo, dom->width);
   1288 	dom->fullname = catstr(dom->varinfo.prefix, dom->name);
   1289 }
   1290 
   1291 static void prepenum(struct rnndb *db, struct rnnenum *en) {
   1292 	if (en->prepared)
   1293 		return;
   1294 	prepvarinfo (db, en->name, &en->varinfo, 0);
   1295 	int i;
   1296 	if (en->isinline)
   1297 		return;
   1298 	for (i = 0; i < en->valsnum; i++)
   1299 		prepvalue(db, en->vals[i], en->bare?0:en->name, &en->varinfo);
   1300 	en->fullname = catstr(en->varinfo.prefix, en->name);
   1301 	en->prepared = 1;
   1302 }
   1303 
   1304 static void prepbitset(struct rnndb *db, struct rnnbitset *bs) {
   1305 	prepvarinfo (db, bs->name, &bs->varinfo, 0);
   1306 	int i;
   1307 	if (bs->isinline)
   1308 		return;
   1309 	for (i = 0; i < bs->bitfieldsnum; i++)
   1310 		prepbitfield(db, bs->bitfields[i], bs->bare?0:bs->name, &bs->varinfo);
   1311 	bs->fullname = catstr(bs->varinfo.prefix, bs->name);
   1312 }
   1313 
   1314 static void prepspectype(struct rnndb *db, struct rnnspectype *st) {
   1315 	preptypeinfo(db, &st->typeinfo, st->name, 0, st->file); // XXX doesn't exactly make sense...
   1316 }
   1317 
   1318 void rnn_prepdb (struct rnndb *db) {
   1319 	int i;
   1320 	for (i = 0; i < db->enumsnum; i++)
   1321 		prepenum(db, db->enums[i]);
   1322 	for (i = 0; i < db->bitsetsnum; i++)
   1323 		prepbitset(db, db->bitsets[i]);
   1324 	for (i = 0; i < db->domainsnum; i++)
   1325 		prepdomain(db, db->domains[i]);
   1326 	for (i = 0; i < db->spectypesnum; i++)
   1327 		prepspectype(db, db->spectypes[i]);
   1328 }
   1329 
   1330 struct rnnenum *rnn_findenum (struct rnndb *db, const char *name) {
   1331 	int i;
   1332 	for (i = 0; i < db->enumsnum; i++)
   1333 		if (!strcmp(db->enums[i]->name, name))
   1334 			return db->enums[i];
   1335 	return 0;
   1336 }
   1337 
   1338 struct rnnbitset *rnn_findbitset (struct rnndb *db, const char *name) {
   1339 	int i;
   1340 	for (i = 0; i < db->bitsetsnum; i++)
   1341 		if (!strcmp(db->bitsets[i]->name, name))
   1342 			return db->bitsets[i];
   1343 	return 0;
   1344 }
   1345 
   1346 struct rnndomain *rnn_finddomain (struct rnndb *db, const char *name) {
   1347 	int i;
   1348 	for (i = 0; i < db->domainsnum; i++)
   1349 		if (!strcmp(db->domains[i]->name, name))
   1350 			return db->domains[i];
   1351 	return 0;
   1352 }
   1353 
   1354 struct rnnspectype *rnn_findspectype (struct rnndb *db, const char *name) {
   1355 	int i;
   1356 	for (i = 0; i < db->spectypesnum; i++)
   1357 		if (!strcmp(db->spectypes[i]->name, name))
   1358 			return db->spectypes[i];
   1359 	return 0;
   1360 }
   1361