162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *      names.c  --  USB name database manipulation routines
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *      Copyright (C) 1999, 2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *	Copyright (C) 2005 Takahiro Hirofuchi
862306a36Sopenharmony_ci *		- names_deinit() is added.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <sys/types.h>
1262306a36Sopenharmony_ci#include <sys/stat.h>
1362306a36Sopenharmony_ci#include <fcntl.h>
1462306a36Sopenharmony_ci#include <dirent.h>
1562306a36Sopenharmony_ci#include <string.h>
1662306a36Sopenharmony_ci#include <errno.h>
1762306a36Sopenharmony_ci#include <stdlib.h>
1862306a36Sopenharmony_ci#include <unistd.h>
1962306a36Sopenharmony_ci#include <stdio.h>
2062306a36Sopenharmony_ci#include <ctype.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "names.h"
2362306a36Sopenharmony_ci#include "usbip_common.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistruct vendor {
2662306a36Sopenharmony_ci	struct vendor *next;
2762306a36Sopenharmony_ci	u_int16_t vendorid;
2862306a36Sopenharmony_ci	char name[1];
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct product {
3262306a36Sopenharmony_ci	struct product *next;
3362306a36Sopenharmony_ci	u_int16_t vendorid, productid;
3462306a36Sopenharmony_ci	char name[1];
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistruct class {
3862306a36Sopenharmony_ci	struct class *next;
3962306a36Sopenharmony_ci	u_int8_t classid;
4062306a36Sopenharmony_ci	char name[1];
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct subclass {
4462306a36Sopenharmony_ci	struct subclass *next;
4562306a36Sopenharmony_ci	u_int8_t classid, subclassid;
4662306a36Sopenharmony_ci	char name[1];
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistruct protocol {
5062306a36Sopenharmony_ci	struct protocol *next;
5162306a36Sopenharmony_ci	u_int8_t classid, subclassid, protocolid;
5262306a36Sopenharmony_ci	char name[1];
5362306a36Sopenharmony_ci};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistruct genericstrtable {
5662306a36Sopenharmony_ci	struct genericstrtable *next;
5762306a36Sopenharmony_ci	unsigned int num;
5862306a36Sopenharmony_ci	char name[1];
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define HASH1  0x10
6362306a36Sopenharmony_ci#define HASH2  0x02
6462306a36Sopenharmony_ci#define HASHSZ 16
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic unsigned int hashnum(unsigned int num)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1)
7162306a36Sopenharmony_ci		if (num & mask1)
7262306a36Sopenharmony_ci			num ^= mask2;
7362306a36Sopenharmony_ci	return num & (HASHSZ-1);
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic struct vendor *vendors[HASHSZ] = { NULL, };
7862306a36Sopenharmony_cistatic struct product *products[HASHSZ] = { NULL, };
7962306a36Sopenharmony_cistatic struct class *classes[HASHSZ] = { NULL, };
8062306a36Sopenharmony_cistatic struct subclass *subclasses[HASHSZ] = { NULL, };
8162306a36Sopenharmony_cistatic struct protocol *protocols[HASHSZ] = { NULL, };
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ciconst char *names_vendor(u_int16_t vendorid)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	struct vendor *v;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	v = vendors[hashnum(vendorid)];
8862306a36Sopenharmony_ci	for (; v; v = v->next)
8962306a36Sopenharmony_ci		if (v->vendorid == vendorid)
9062306a36Sopenharmony_ci			return v->name;
9162306a36Sopenharmony_ci	return NULL;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ciconst char *names_product(u_int16_t vendorid, u_int16_t productid)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	struct product *p;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	p = products[hashnum((vendorid << 16) | productid)];
9962306a36Sopenharmony_ci	for (; p; p = p->next)
10062306a36Sopenharmony_ci		if (p->vendorid == vendorid && p->productid == productid)
10162306a36Sopenharmony_ci			return p->name;
10262306a36Sopenharmony_ci	return NULL;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ciconst char *names_class(u_int8_t classid)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	struct class *c;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	c = classes[hashnum(classid)];
11062306a36Sopenharmony_ci	for (; c; c = c->next)
11162306a36Sopenharmony_ci		if (c->classid == classid)
11262306a36Sopenharmony_ci			return c->name;
11362306a36Sopenharmony_ci	return NULL;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ciconst char *names_subclass(u_int8_t classid, u_int8_t subclassid)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct subclass *s;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	s = subclasses[hashnum((classid << 8) | subclassid)];
12162306a36Sopenharmony_ci	for (; s; s = s->next)
12262306a36Sopenharmony_ci		if (s->classid == classid && s->subclassid == subclassid)
12362306a36Sopenharmony_ci			return s->name;
12462306a36Sopenharmony_ci	return NULL;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ciconst char *names_protocol(u_int8_t classid, u_int8_t subclassid,
12862306a36Sopenharmony_ci			   u_int8_t protocolid)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct protocol *p;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	p = protocols[hashnum((classid << 16) | (subclassid << 8)
13362306a36Sopenharmony_ci			      | protocolid)];
13462306a36Sopenharmony_ci	for (; p; p = p->next)
13562306a36Sopenharmony_ci		if (p->classid == classid && p->subclassid == subclassid &&
13662306a36Sopenharmony_ci		    p->protocolid == protocolid)
13762306a36Sopenharmony_ci			return p->name;
13862306a36Sopenharmony_ci	return NULL;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/* add a cleanup function by takahiro */
14262306a36Sopenharmony_cistruct pool {
14362306a36Sopenharmony_ci	struct pool *next;
14462306a36Sopenharmony_ci	void *mem;
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic struct pool *pool_head;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic void *my_malloc(size_t size)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct pool *p;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	p = calloc(1, sizeof(struct pool));
15462306a36Sopenharmony_ci	if (!p)
15562306a36Sopenharmony_ci		return NULL;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	p->mem = calloc(1, size);
15862306a36Sopenharmony_ci	if (!p->mem) {
15962306a36Sopenharmony_ci		free(p);
16062306a36Sopenharmony_ci		return NULL;
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	p->next = pool_head;
16462306a36Sopenharmony_ci	pool_head = p;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	return p->mem;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_civoid names_free(void)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct pool *pool;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	if (!pool_head)
17462306a36Sopenharmony_ci		return;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	for (pool = pool_head; pool != NULL; ) {
17762306a36Sopenharmony_ci		struct pool *tmp;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci		if (pool->mem)
18062306a36Sopenharmony_ci			free(pool->mem);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci		tmp = pool;
18362306a36Sopenharmony_ci		pool = pool->next;
18462306a36Sopenharmony_ci		free(tmp);
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic int new_vendor(const char *name, u_int16_t vendorid)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	struct vendor *v;
19162306a36Sopenharmony_ci	unsigned int h = hashnum(vendorid);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	v = vendors[h];
19462306a36Sopenharmony_ci	for (; v; v = v->next)
19562306a36Sopenharmony_ci		if (v->vendorid == vendorid)
19662306a36Sopenharmony_ci			return -1;
19762306a36Sopenharmony_ci	v = my_malloc(sizeof(struct vendor) + strlen(name));
19862306a36Sopenharmony_ci	if (!v)
19962306a36Sopenharmony_ci		return -1;
20062306a36Sopenharmony_ci	strcpy(v->name, name);
20162306a36Sopenharmony_ci	v->vendorid = vendorid;
20262306a36Sopenharmony_ci	v->next = vendors[h];
20362306a36Sopenharmony_ci	vendors[h] = v;
20462306a36Sopenharmony_ci	return 0;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic int new_product(const char *name, u_int16_t vendorid,
20862306a36Sopenharmony_ci		       u_int16_t productid)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	struct product *p;
21162306a36Sopenharmony_ci	unsigned int h = hashnum((vendorid << 16) | productid);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	p = products[h];
21462306a36Sopenharmony_ci	for (; p; p = p->next)
21562306a36Sopenharmony_ci		if (p->vendorid == vendorid && p->productid == productid)
21662306a36Sopenharmony_ci			return -1;
21762306a36Sopenharmony_ci	p = my_malloc(sizeof(struct product) + strlen(name));
21862306a36Sopenharmony_ci	if (!p)
21962306a36Sopenharmony_ci		return -1;
22062306a36Sopenharmony_ci	strcpy(p->name, name);
22162306a36Sopenharmony_ci	p->vendorid = vendorid;
22262306a36Sopenharmony_ci	p->productid = productid;
22362306a36Sopenharmony_ci	p->next = products[h];
22462306a36Sopenharmony_ci	products[h] = p;
22562306a36Sopenharmony_ci	return 0;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic int new_class(const char *name, u_int8_t classid)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	struct class *c;
23162306a36Sopenharmony_ci	unsigned int h = hashnum(classid);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	c = classes[h];
23462306a36Sopenharmony_ci	for (; c; c = c->next)
23562306a36Sopenharmony_ci		if (c->classid == classid)
23662306a36Sopenharmony_ci			return -1;
23762306a36Sopenharmony_ci	c = my_malloc(sizeof(struct class) + strlen(name));
23862306a36Sopenharmony_ci	if (!c)
23962306a36Sopenharmony_ci		return -1;
24062306a36Sopenharmony_ci	strcpy(c->name, name);
24162306a36Sopenharmony_ci	c->classid = classid;
24262306a36Sopenharmony_ci	c->next = classes[h];
24362306a36Sopenharmony_ci	classes[h] = c;
24462306a36Sopenharmony_ci	return 0;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	struct subclass *s;
25062306a36Sopenharmony_ci	unsigned int h = hashnum((classid << 8) | subclassid);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	s = subclasses[h];
25362306a36Sopenharmony_ci	for (; s; s = s->next)
25462306a36Sopenharmony_ci		if (s->classid == classid && s->subclassid == subclassid)
25562306a36Sopenharmony_ci			return -1;
25662306a36Sopenharmony_ci	s = my_malloc(sizeof(struct subclass) + strlen(name));
25762306a36Sopenharmony_ci	if (!s)
25862306a36Sopenharmony_ci		return -1;
25962306a36Sopenharmony_ci	strcpy(s->name, name);
26062306a36Sopenharmony_ci	s->classid = classid;
26162306a36Sopenharmony_ci	s->subclassid = subclassid;
26262306a36Sopenharmony_ci	s->next = subclasses[h];
26362306a36Sopenharmony_ci	subclasses[h] = s;
26462306a36Sopenharmony_ci	return 0;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid,
26862306a36Sopenharmony_ci			u_int8_t protocolid)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	struct protocol *p;
27162306a36Sopenharmony_ci	unsigned int h = hashnum((classid << 16) | (subclassid << 8)
27262306a36Sopenharmony_ci				 | protocolid);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	p = protocols[h];
27562306a36Sopenharmony_ci	for (; p; p = p->next)
27662306a36Sopenharmony_ci		if (p->classid == classid && p->subclassid == subclassid
27762306a36Sopenharmony_ci		    && p->protocolid == protocolid)
27862306a36Sopenharmony_ci			return -1;
27962306a36Sopenharmony_ci	p = my_malloc(sizeof(struct protocol) + strlen(name));
28062306a36Sopenharmony_ci	if (!p)
28162306a36Sopenharmony_ci		return -1;
28262306a36Sopenharmony_ci	strcpy(p->name, name);
28362306a36Sopenharmony_ci	p->classid = classid;
28462306a36Sopenharmony_ci	p->subclassid = subclassid;
28562306a36Sopenharmony_ci	p->protocolid = protocolid;
28662306a36Sopenharmony_ci	p->next = protocols[h];
28762306a36Sopenharmony_ci	protocols[h] = p;
28862306a36Sopenharmony_ci	return 0;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic void parse(FILE *f)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	char buf[512], *cp;
29462306a36Sopenharmony_ci	unsigned int linectr = 0;
29562306a36Sopenharmony_ci	int lastvendor = -1;
29662306a36Sopenharmony_ci	int lastclass = -1;
29762306a36Sopenharmony_ci	int lastsubclass = -1;
29862306a36Sopenharmony_ci	int lasthut = -1;
29962306a36Sopenharmony_ci	int lastlang = -1;
30062306a36Sopenharmony_ci	unsigned int u;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	while (fgets(buf, sizeof(buf), f)) {
30362306a36Sopenharmony_ci		linectr++;
30462306a36Sopenharmony_ci		/* remove line ends */
30562306a36Sopenharmony_ci		cp = strchr(buf, '\r');
30662306a36Sopenharmony_ci		if (cp)
30762306a36Sopenharmony_ci			*cp = 0;
30862306a36Sopenharmony_ci		cp = strchr(buf, '\n');
30962306a36Sopenharmony_ci		if (cp)
31062306a36Sopenharmony_ci			*cp = 0;
31162306a36Sopenharmony_ci		if (buf[0] == '#' || !buf[0])
31262306a36Sopenharmony_ci			continue;
31362306a36Sopenharmony_ci		cp = buf;
31462306a36Sopenharmony_ci		if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' &&
31562306a36Sopenharmony_ci		    buf[3] == 'S' && buf[4] == 'D' &&
31662306a36Sopenharmony_ci		    buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/
31762306a36Sopenharmony_ci		    buf[7] == ' ') {
31862306a36Sopenharmony_ci			continue;
31962306a36Sopenharmony_ci		}
32062306a36Sopenharmony_ci		if (buf[0] == 'P' && buf[1] == 'H' &&
32162306a36Sopenharmony_ci		    buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') {
32262306a36Sopenharmony_ci			continue;
32362306a36Sopenharmony_ci		}
32462306a36Sopenharmony_ci		if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' &&
32562306a36Sopenharmony_ci		    buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') {
32662306a36Sopenharmony_ci			continue;
32762306a36Sopenharmony_ci		}
32862306a36Sopenharmony_ci		if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') {
32962306a36Sopenharmony_ci			lasthut = lastclass = lastvendor = lastsubclass = -1;
33062306a36Sopenharmony_ci			/*
33162306a36Sopenharmony_ci			 * set 1 as pseudo-id to indicate that the parser is
33262306a36Sopenharmony_ci			 * in a `L' section.
33362306a36Sopenharmony_ci			 */
33462306a36Sopenharmony_ci			lastlang = 1;
33562306a36Sopenharmony_ci			continue;
33662306a36Sopenharmony_ci		}
33762306a36Sopenharmony_ci		if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') {
33862306a36Sopenharmony_ci			/* class spec */
33962306a36Sopenharmony_ci			cp = buf+2;
34062306a36Sopenharmony_ci			while (isspace(*cp))
34162306a36Sopenharmony_ci				cp++;
34262306a36Sopenharmony_ci			if (!isxdigit(*cp)) {
34362306a36Sopenharmony_ci				err("Invalid class spec at line %u", linectr);
34462306a36Sopenharmony_ci				continue;
34562306a36Sopenharmony_ci			}
34662306a36Sopenharmony_ci			u = strtoul(cp, &cp, 16);
34762306a36Sopenharmony_ci			while (isspace(*cp))
34862306a36Sopenharmony_ci				cp++;
34962306a36Sopenharmony_ci			if (!*cp) {
35062306a36Sopenharmony_ci				err("Invalid class spec at line %u", linectr);
35162306a36Sopenharmony_ci				continue;
35262306a36Sopenharmony_ci			}
35362306a36Sopenharmony_ci			if (new_class(cp, u))
35462306a36Sopenharmony_ci				err("Duplicate class spec at line %u class %04x %s",
35562306a36Sopenharmony_ci				    linectr, u, cp);
35662306a36Sopenharmony_ci			dbg("line %5u class %02x %s", linectr, u, cp);
35762306a36Sopenharmony_ci			lasthut = lastlang = lastvendor = lastsubclass = -1;
35862306a36Sopenharmony_ci			lastclass = u;
35962306a36Sopenharmony_ci			continue;
36062306a36Sopenharmony_ci		}
36162306a36Sopenharmony_ci		if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) {
36262306a36Sopenharmony_ci			/* audio terminal type spec */
36362306a36Sopenharmony_ci			continue;
36462306a36Sopenharmony_ci		}
36562306a36Sopenharmony_ci		if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C'
36662306a36Sopenharmony_ci		    && isspace(buf[3])) {
36762306a36Sopenharmony_ci			/* HID Descriptor bCountryCode */
36862306a36Sopenharmony_ci			continue;
36962306a36Sopenharmony_ci		}
37062306a36Sopenharmony_ci		if (isxdigit(*cp)) {
37162306a36Sopenharmony_ci			/* vendor */
37262306a36Sopenharmony_ci			u = strtoul(cp, &cp, 16);
37362306a36Sopenharmony_ci			while (isspace(*cp))
37462306a36Sopenharmony_ci				cp++;
37562306a36Sopenharmony_ci			if (!*cp) {
37662306a36Sopenharmony_ci				err("Invalid vendor spec at line %u", linectr);
37762306a36Sopenharmony_ci				continue;
37862306a36Sopenharmony_ci			}
37962306a36Sopenharmony_ci			if (new_vendor(cp, u))
38062306a36Sopenharmony_ci				err("Duplicate vendor spec at line %u vendor %04x %s",
38162306a36Sopenharmony_ci				    linectr, u, cp);
38262306a36Sopenharmony_ci			dbg("line %5u vendor %04x %s", linectr, u, cp);
38362306a36Sopenharmony_ci			lastvendor = u;
38462306a36Sopenharmony_ci			lasthut = lastlang = lastclass = lastsubclass = -1;
38562306a36Sopenharmony_ci			continue;
38662306a36Sopenharmony_ci		}
38762306a36Sopenharmony_ci		if (buf[0] == '\t' && isxdigit(buf[1])) {
38862306a36Sopenharmony_ci			/* product or subclass spec */
38962306a36Sopenharmony_ci			u = strtoul(buf+1, &cp, 16);
39062306a36Sopenharmony_ci			while (isspace(*cp))
39162306a36Sopenharmony_ci				cp++;
39262306a36Sopenharmony_ci			if (!*cp) {
39362306a36Sopenharmony_ci				err("Invalid product/subclass spec at line %u",
39462306a36Sopenharmony_ci				    linectr);
39562306a36Sopenharmony_ci				continue;
39662306a36Sopenharmony_ci			}
39762306a36Sopenharmony_ci			if (lastvendor != -1) {
39862306a36Sopenharmony_ci				if (new_product(cp, lastvendor, u))
39962306a36Sopenharmony_ci					err("Duplicate product spec at line %u product %04x:%04x %s",
40062306a36Sopenharmony_ci					    linectr, lastvendor, u, cp);
40162306a36Sopenharmony_ci				dbg("line %5u product %04x:%04x %s", linectr,
40262306a36Sopenharmony_ci				    lastvendor, u, cp);
40362306a36Sopenharmony_ci				continue;
40462306a36Sopenharmony_ci			}
40562306a36Sopenharmony_ci			if (lastclass != -1) {
40662306a36Sopenharmony_ci				if (new_subclass(cp, lastclass, u))
40762306a36Sopenharmony_ci					err("Duplicate subclass spec at line %u class %02x:%02x %s",
40862306a36Sopenharmony_ci					    linectr, lastclass, u, cp);
40962306a36Sopenharmony_ci				dbg("line %5u subclass %02x:%02x %s", linectr,
41062306a36Sopenharmony_ci				    lastclass, u, cp);
41162306a36Sopenharmony_ci				lastsubclass = u;
41262306a36Sopenharmony_ci				continue;
41362306a36Sopenharmony_ci			}
41462306a36Sopenharmony_ci			if (lasthut != -1) {
41562306a36Sopenharmony_ci				/* do not store hut */
41662306a36Sopenharmony_ci				continue;
41762306a36Sopenharmony_ci			}
41862306a36Sopenharmony_ci			if (lastlang != -1) {
41962306a36Sopenharmony_ci				/* do not store langid */
42062306a36Sopenharmony_ci				continue;
42162306a36Sopenharmony_ci			}
42262306a36Sopenharmony_ci			err("Product/Subclass spec without prior Vendor/Class spec at line %u",
42362306a36Sopenharmony_ci			    linectr);
42462306a36Sopenharmony_ci			continue;
42562306a36Sopenharmony_ci		}
42662306a36Sopenharmony_ci		if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) {
42762306a36Sopenharmony_ci			/* protocol spec */
42862306a36Sopenharmony_ci			u = strtoul(buf+2, &cp, 16);
42962306a36Sopenharmony_ci			while (isspace(*cp))
43062306a36Sopenharmony_ci				cp++;
43162306a36Sopenharmony_ci			if (!*cp) {
43262306a36Sopenharmony_ci				err("Invalid protocol spec at line %u",
43362306a36Sopenharmony_ci				    linectr);
43462306a36Sopenharmony_ci				continue;
43562306a36Sopenharmony_ci			}
43662306a36Sopenharmony_ci			if (lastclass != -1 && lastsubclass != -1) {
43762306a36Sopenharmony_ci				if (new_protocol(cp, lastclass, lastsubclass,
43862306a36Sopenharmony_ci						 u))
43962306a36Sopenharmony_ci					err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s",
44062306a36Sopenharmony_ci					    linectr, lastclass, lastsubclass,
44162306a36Sopenharmony_ci					    u, cp);
44262306a36Sopenharmony_ci				dbg("line %5u protocol %02x:%02x:%02x %s",
44362306a36Sopenharmony_ci				    linectr, lastclass, lastsubclass, u, cp);
44462306a36Sopenharmony_ci				continue;
44562306a36Sopenharmony_ci			}
44662306a36Sopenharmony_ci			err("Protocol spec without prior Class and Subclass spec at line %u",
44762306a36Sopenharmony_ci			    linectr);
44862306a36Sopenharmony_ci			continue;
44962306a36Sopenharmony_ci		}
45062306a36Sopenharmony_ci		if (buf[0] == 'H' && buf[1] == 'I' &&
45162306a36Sopenharmony_ci		    buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') {
45262306a36Sopenharmony_ci			continue;
45362306a36Sopenharmony_ci		}
45462306a36Sopenharmony_ci		if (buf[0] == 'H' && buf[1] == 'U' &&
45562306a36Sopenharmony_ci		    buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') {
45662306a36Sopenharmony_ci			lastlang = lastclass = lastvendor = lastsubclass = -1;
45762306a36Sopenharmony_ci			/*
45862306a36Sopenharmony_ci			 * set 1 as pseudo-id to indicate that the parser is
45962306a36Sopenharmony_ci			 * in a `HUT' section.
46062306a36Sopenharmony_ci			 */
46162306a36Sopenharmony_ci			lasthut = 1;
46262306a36Sopenharmony_ci			continue;
46362306a36Sopenharmony_ci		}
46462306a36Sopenharmony_ci		if (buf[0] == 'R' && buf[1] == ' ')
46562306a36Sopenharmony_ci			continue;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci		if (buf[0] == 'V' && buf[1] == 'T')
46862306a36Sopenharmony_ci			continue;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci		err("Unknown line at line %u", linectr);
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ciint names_init(char *n)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	FILE *f;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	f = fopen(n, "r");
48062306a36Sopenharmony_ci	if (!f)
48162306a36Sopenharmony_ci		return errno;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	parse(f);
48462306a36Sopenharmony_ci	fclose(f);
48562306a36Sopenharmony_ci	return 0;
48662306a36Sopenharmony_ci}
487