18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *      names.c  --  USB name database manipulation routines
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *      Copyright (C) 1999, 2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *	Copyright (C) 2005 Takahiro Hirofuchi
88c2ecf20Sopenharmony_ci *		- names_deinit() is added.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <sys/types.h>
128c2ecf20Sopenharmony_ci#include <sys/stat.h>
138c2ecf20Sopenharmony_ci#include <fcntl.h>
148c2ecf20Sopenharmony_ci#include <dirent.h>
158c2ecf20Sopenharmony_ci#include <string.h>
168c2ecf20Sopenharmony_ci#include <errno.h>
178c2ecf20Sopenharmony_ci#include <stdlib.h>
188c2ecf20Sopenharmony_ci#include <unistd.h>
198c2ecf20Sopenharmony_ci#include <stdio.h>
208c2ecf20Sopenharmony_ci#include <ctype.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include "names.h"
238c2ecf20Sopenharmony_ci#include "usbip_common.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistruct vendor {
268c2ecf20Sopenharmony_ci	struct vendor *next;
278c2ecf20Sopenharmony_ci	u_int16_t vendorid;
288c2ecf20Sopenharmony_ci	char name[1];
298c2ecf20Sopenharmony_ci};
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistruct product {
328c2ecf20Sopenharmony_ci	struct product *next;
338c2ecf20Sopenharmony_ci	u_int16_t vendorid, productid;
348c2ecf20Sopenharmony_ci	char name[1];
358c2ecf20Sopenharmony_ci};
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistruct class {
388c2ecf20Sopenharmony_ci	struct class *next;
398c2ecf20Sopenharmony_ci	u_int8_t classid;
408c2ecf20Sopenharmony_ci	char name[1];
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistruct subclass {
448c2ecf20Sopenharmony_ci	struct subclass *next;
458c2ecf20Sopenharmony_ci	u_int8_t classid, subclassid;
468c2ecf20Sopenharmony_ci	char name[1];
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistruct protocol {
508c2ecf20Sopenharmony_ci	struct protocol *next;
518c2ecf20Sopenharmony_ci	u_int8_t classid, subclassid, protocolid;
528c2ecf20Sopenharmony_ci	char name[1];
538c2ecf20Sopenharmony_ci};
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistruct genericstrtable {
568c2ecf20Sopenharmony_ci	struct genericstrtable *next;
578c2ecf20Sopenharmony_ci	unsigned int num;
588c2ecf20Sopenharmony_ci	char name[1];
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#define HASH1  0x10
638c2ecf20Sopenharmony_ci#define HASH2  0x02
648c2ecf20Sopenharmony_ci#define HASHSZ 16
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic unsigned int hashnum(unsigned int num)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1)
718c2ecf20Sopenharmony_ci		if (num & mask1)
728c2ecf20Sopenharmony_ci			num ^= mask2;
738c2ecf20Sopenharmony_ci	return num & (HASHSZ-1);
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic struct vendor *vendors[HASHSZ] = { NULL, };
788c2ecf20Sopenharmony_cistatic struct product *products[HASHSZ] = { NULL, };
798c2ecf20Sopenharmony_cistatic struct class *classes[HASHSZ] = { NULL, };
808c2ecf20Sopenharmony_cistatic struct subclass *subclasses[HASHSZ] = { NULL, };
818c2ecf20Sopenharmony_cistatic struct protocol *protocols[HASHSZ] = { NULL, };
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ciconst char *names_vendor(u_int16_t vendorid)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	struct vendor *v;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	v = vendors[hashnum(vendorid)];
888c2ecf20Sopenharmony_ci	for (; v; v = v->next)
898c2ecf20Sopenharmony_ci		if (v->vendorid == vendorid)
908c2ecf20Sopenharmony_ci			return v->name;
918c2ecf20Sopenharmony_ci	return NULL;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ciconst char *names_product(u_int16_t vendorid, u_int16_t productid)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	struct product *p;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	p = products[hashnum((vendorid << 16) | productid)];
998c2ecf20Sopenharmony_ci	for (; p; p = p->next)
1008c2ecf20Sopenharmony_ci		if (p->vendorid == vendorid && p->productid == productid)
1018c2ecf20Sopenharmony_ci			return p->name;
1028c2ecf20Sopenharmony_ci	return NULL;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ciconst char *names_class(u_int8_t classid)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	struct class *c;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	c = classes[hashnum(classid)];
1108c2ecf20Sopenharmony_ci	for (; c; c = c->next)
1118c2ecf20Sopenharmony_ci		if (c->classid == classid)
1128c2ecf20Sopenharmony_ci			return c->name;
1138c2ecf20Sopenharmony_ci	return NULL;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ciconst char *names_subclass(u_int8_t classid, u_int8_t subclassid)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct subclass *s;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	s = subclasses[hashnum((classid << 8) | subclassid)];
1218c2ecf20Sopenharmony_ci	for (; s; s = s->next)
1228c2ecf20Sopenharmony_ci		if (s->classid == classid && s->subclassid == subclassid)
1238c2ecf20Sopenharmony_ci			return s->name;
1248c2ecf20Sopenharmony_ci	return NULL;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ciconst char *names_protocol(u_int8_t classid, u_int8_t subclassid,
1288c2ecf20Sopenharmony_ci			   u_int8_t protocolid)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	struct protocol *p;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	p = protocols[hashnum((classid << 16) | (subclassid << 8)
1338c2ecf20Sopenharmony_ci			      | protocolid)];
1348c2ecf20Sopenharmony_ci	for (; p; p = p->next)
1358c2ecf20Sopenharmony_ci		if (p->classid == classid && p->subclassid == subclassid &&
1368c2ecf20Sopenharmony_ci		    p->protocolid == protocolid)
1378c2ecf20Sopenharmony_ci			return p->name;
1388c2ecf20Sopenharmony_ci	return NULL;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci/* add a cleanup function by takahiro */
1428c2ecf20Sopenharmony_cistruct pool {
1438c2ecf20Sopenharmony_ci	struct pool *next;
1448c2ecf20Sopenharmony_ci	void *mem;
1458c2ecf20Sopenharmony_ci};
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic struct pool *pool_head;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic void *my_malloc(size_t size)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct pool *p;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	p = calloc(1, sizeof(struct pool));
1548c2ecf20Sopenharmony_ci	if (!p)
1558c2ecf20Sopenharmony_ci		return NULL;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	p->mem = calloc(1, size);
1588c2ecf20Sopenharmony_ci	if (!p->mem) {
1598c2ecf20Sopenharmony_ci		free(p);
1608c2ecf20Sopenharmony_ci		return NULL;
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	p->next = pool_head;
1648c2ecf20Sopenharmony_ci	pool_head = p;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	return p->mem;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_civoid names_free(void)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	struct pool *pool;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	if (!pool_head)
1748c2ecf20Sopenharmony_ci		return;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	for (pool = pool_head; pool != NULL; ) {
1778c2ecf20Sopenharmony_ci		struct pool *tmp;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci		if (pool->mem)
1808c2ecf20Sopenharmony_ci			free(pool->mem);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci		tmp = pool;
1838c2ecf20Sopenharmony_ci		pool = pool->next;
1848c2ecf20Sopenharmony_ci		free(tmp);
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic int new_vendor(const char *name, u_int16_t vendorid)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	struct vendor *v;
1918c2ecf20Sopenharmony_ci	unsigned int h = hashnum(vendorid);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	v = vendors[h];
1948c2ecf20Sopenharmony_ci	for (; v; v = v->next)
1958c2ecf20Sopenharmony_ci		if (v->vendorid == vendorid)
1968c2ecf20Sopenharmony_ci			return -1;
1978c2ecf20Sopenharmony_ci	v = my_malloc(sizeof(struct vendor) + strlen(name));
1988c2ecf20Sopenharmony_ci	if (!v)
1998c2ecf20Sopenharmony_ci		return -1;
2008c2ecf20Sopenharmony_ci	strcpy(v->name, name);
2018c2ecf20Sopenharmony_ci	v->vendorid = vendorid;
2028c2ecf20Sopenharmony_ci	v->next = vendors[h];
2038c2ecf20Sopenharmony_ci	vendors[h] = v;
2048c2ecf20Sopenharmony_ci	return 0;
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic int new_product(const char *name, u_int16_t vendorid,
2088c2ecf20Sopenharmony_ci		       u_int16_t productid)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	struct product *p;
2118c2ecf20Sopenharmony_ci	unsigned int h = hashnum((vendorid << 16) | productid);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	p = products[h];
2148c2ecf20Sopenharmony_ci	for (; p; p = p->next)
2158c2ecf20Sopenharmony_ci		if (p->vendorid == vendorid && p->productid == productid)
2168c2ecf20Sopenharmony_ci			return -1;
2178c2ecf20Sopenharmony_ci	p = my_malloc(sizeof(struct product) + strlen(name));
2188c2ecf20Sopenharmony_ci	if (!p)
2198c2ecf20Sopenharmony_ci		return -1;
2208c2ecf20Sopenharmony_ci	strcpy(p->name, name);
2218c2ecf20Sopenharmony_ci	p->vendorid = vendorid;
2228c2ecf20Sopenharmony_ci	p->productid = productid;
2238c2ecf20Sopenharmony_ci	p->next = products[h];
2248c2ecf20Sopenharmony_ci	products[h] = p;
2258c2ecf20Sopenharmony_ci	return 0;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic int new_class(const char *name, u_int8_t classid)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	struct class *c;
2318c2ecf20Sopenharmony_ci	unsigned int h = hashnum(classid);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	c = classes[h];
2348c2ecf20Sopenharmony_ci	for (; c; c = c->next)
2358c2ecf20Sopenharmony_ci		if (c->classid == classid)
2368c2ecf20Sopenharmony_ci			return -1;
2378c2ecf20Sopenharmony_ci	c = my_malloc(sizeof(struct class) + strlen(name));
2388c2ecf20Sopenharmony_ci	if (!c)
2398c2ecf20Sopenharmony_ci		return -1;
2408c2ecf20Sopenharmony_ci	strcpy(c->name, name);
2418c2ecf20Sopenharmony_ci	c->classid = classid;
2428c2ecf20Sopenharmony_ci	c->next = classes[h];
2438c2ecf20Sopenharmony_ci	classes[h] = c;
2448c2ecf20Sopenharmony_ci	return 0;
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	struct subclass *s;
2508c2ecf20Sopenharmony_ci	unsigned int h = hashnum((classid << 8) | subclassid);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	s = subclasses[h];
2538c2ecf20Sopenharmony_ci	for (; s; s = s->next)
2548c2ecf20Sopenharmony_ci		if (s->classid == classid && s->subclassid == subclassid)
2558c2ecf20Sopenharmony_ci			return -1;
2568c2ecf20Sopenharmony_ci	s = my_malloc(sizeof(struct subclass) + strlen(name));
2578c2ecf20Sopenharmony_ci	if (!s)
2588c2ecf20Sopenharmony_ci		return -1;
2598c2ecf20Sopenharmony_ci	strcpy(s->name, name);
2608c2ecf20Sopenharmony_ci	s->classid = classid;
2618c2ecf20Sopenharmony_ci	s->subclassid = subclassid;
2628c2ecf20Sopenharmony_ci	s->next = subclasses[h];
2638c2ecf20Sopenharmony_ci	subclasses[h] = s;
2648c2ecf20Sopenharmony_ci	return 0;
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistatic int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid,
2688c2ecf20Sopenharmony_ci			u_int8_t protocolid)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	struct protocol *p;
2718c2ecf20Sopenharmony_ci	unsigned int h = hashnum((classid << 16) | (subclassid << 8)
2728c2ecf20Sopenharmony_ci				 | protocolid);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	p = protocols[h];
2758c2ecf20Sopenharmony_ci	for (; p; p = p->next)
2768c2ecf20Sopenharmony_ci		if (p->classid == classid && p->subclassid == subclassid
2778c2ecf20Sopenharmony_ci		    && p->protocolid == protocolid)
2788c2ecf20Sopenharmony_ci			return -1;
2798c2ecf20Sopenharmony_ci	p = my_malloc(sizeof(struct protocol) + strlen(name));
2808c2ecf20Sopenharmony_ci	if (!p)
2818c2ecf20Sopenharmony_ci		return -1;
2828c2ecf20Sopenharmony_ci	strcpy(p->name, name);
2838c2ecf20Sopenharmony_ci	p->classid = classid;
2848c2ecf20Sopenharmony_ci	p->subclassid = subclassid;
2858c2ecf20Sopenharmony_ci	p->protocolid = protocolid;
2868c2ecf20Sopenharmony_ci	p->next = protocols[h];
2878c2ecf20Sopenharmony_ci	protocols[h] = p;
2888c2ecf20Sopenharmony_ci	return 0;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic void parse(FILE *f)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	char buf[512], *cp;
2948c2ecf20Sopenharmony_ci	unsigned int linectr = 0;
2958c2ecf20Sopenharmony_ci	int lastvendor = -1;
2968c2ecf20Sopenharmony_ci	int lastclass = -1;
2978c2ecf20Sopenharmony_ci	int lastsubclass = -1;
2988c2ecf20Sopenharmony_ci	int lasthut = -1;
2998c2ecf20Sopenharmony_ci	int lastlang = -1;
3008c2ecf20Sopenharmony_ci	unsigned int u;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	while (fgets(buf, sizeof(buf), f)) {
3038c2ecf20Sopenharmony_ci		linectr++;
3048c2ecf20Sopenharmony_ci		/* remove line ends */
3058c2ecf20Sopenharmony_ci		cp = strchr(buf, '\r');
3068c2ecf20Sopenharmony_ci		if (cp)
3078c2ecf20Sopenharmony_ci			*cp = 0;
3088c2ecf20Sopenharmony_ci		cp = strchr(buf, '\n');
3098c2ecf20Sopenharmony_ci		if (cp)
3108c2ecf20Sopenharmony_ci			*cp = 0;
3118c2ecf20Sopenharmony_ci		if (buf[0] == '#' || !buf[0])
3128c2ecf20Sopenharmony_ci			continue;
3138c2ecf20Sopenharmony_ci		cp = buf;
3148c2ecf20Sopenharmony_ci		if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' &&
3158c2ecf20Sopenharmony_ci		    buf[3] == 'S' && buf[4] == 'D' &&
3168c2ecf20Sopenharmony_ci		    buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/
3178c2ecf20Sopenharmony_ci		    buf[7] == ' ') {
3188c2ecf20Sopenharmony_ci			continue;
3198c2ecf20Sopenharmony_ci		}
3208c2ecf20Sopenharmony_ci		if (buf[0] == 'P' && buf[1] == 'H' &&
3218c2ecf20Sopenharmony_ci		    buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') {
3228c2ecf20Sopenharmony_ci			continue;
3238c2ecf20Sopenharmony_ci		}
3248c2ecf20Sopenharmony_ci		if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' &&
3258c2ecf20Sopenharmony_ci		    buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') {
3268c2ecf20Sopenharmony_ci			continue;
3278c2ecf20Sopenharmony_ci		}
3288c2ecf20Sopenharmony_ci		if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') {
3298c2ecf20Sopenharmony_ci			lasthut = lastclass = lastvendor = lastsubclass = -1;
3308c2ecf20Sopenharmony_ci			/*
3318c2ecf20Sopenharmony_ci			 * set 1 as pseudo-id to indicate that the parser is
3328c2ecf20Sopenharmony_ci			 * in a `L' section.
3338c2ecf20Sopenharmony_ci			 */
3348c2ecf20Sopenharmony_ci			lastlang = 1;
3358c2ecf20Sopenharmony_ci			continue;
3368c2ecf20Sopenharmony_ci		}
3378c2ecf20Sopenharmony_ci		if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') {
3388c2ecf20Sopenharmony_ci			/* class spec */
3398c2ecf20Sopenharmony_ci			cp = buf+2;
3408c2ecf20Sopenharmony_ci			while (isspace(*cp))
3418c2ecf20Sopenharmony_ci				cp++;
3428c2ecf20Sopenharmony_ci			if (!isxdigit(*cp)) {
3438c2ecf20Sopenharmony_ci				err("Invalid class spec at line %u", linectr);
3448c2ecf20Sopenharmony_ci				continue;
3458c2ecf20Sopenharmony_ci			}
3468c2ecf20Sopenharmony_ci			u = strtoul(cp, &cp, 16);
3478c2ecf20Sopenharmony_ci			while (isspace(*cp))
3488c2ecf20Sopenharmony_ci				cp++;
3498c2ecf20Sopenharmony_ci			if (!*cp) {
3508c2ecf20Sopenharmony_ci				err("Invalid class spec at line %u", linectr);
3518c2ecf20Sopenharmony_ci				continue;
3528c2ecf20Sopenharmony_ci			}
3538c2ecf20Sopenharmony_ci			if (new_class(cp, u))
3548c2ecf20Sopenharmony_ci				err("Duplicate class spec at line %u class %04x %s",
3558c2ecf20Sopenharmony_ci				    linectr, u, cp);
3568c2ecf20Sopenharmony_ci			dbg("line %5u class %02x %s", linectr, u, cp);
3578c2ecf20Sopenharmony_ci			lasthut = lastlang = lastvendor = lastsubclass = -1;
3588c2ecf20Sopenharmony_ci			lastclass = u;
3598c2ecf20Sopenharmony_ci			continue;
3608c2ecf20Sopenharmony_ci		}
3618c2ecf20Sopenharmony_ci		if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) {
3628c2ecf20Sopenharmony_ci			/* audio terminal type spec */
3638c2ecf20Sopenharmony_ci			continue;
3648c2ecf20Sopenharmony_ci		}
3658c2ecf20Sopenharmony_ci		if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C'
3668c2ecf20Sopenharmony_ci		    && isspace(buf[3])) {
3678c2ecf20Sopenharmony_ci			/* HID Descriptor bCountryCode */
3688c2ecf20Sopenharmony_ci			continue;
3698c2ecf20Sopenharmony_ci		}
3708c2ecf20Sopenharmony_ci		if (isxdigit(*cp)) {
3718c2ecf20Sopenharmony_ci			/* vendor */
3728c2ecf20Sopenharmony_ci			u = strtoul(cp, &cp, 16);
3738c2ecf20Sopenharmony_ci			while (isspace(*cp))
3748c2ecf20Sopenharmony_ci				cp++;
3758c2ecf20Sopenharmony_ci			if (!*cp) {
3768c2ecf20Sopenharmony_ci				err("Invalid vendor spec at line %u", linectr);
3778c2ecf20Sopenharmony_ci				continue;
3788c2ecf20Sopenharmony_ci			}
3798c2ecf20Sopenharmony_ci			if (new_vendor(cp, u))
3808c2ecf20Sopenharmony_ci				err("Duplicate vendor spec at line %u vendor %04x %s",
3818c2ecf20Sopenharmony_ci				    linectr, u, cp);
3828c2ecf20Sopenharmony_ci			dbg("line %5u vendor %04x %s", linectr, u, cp);
3838c2ecf20Sopenharmony_ci			lastvendor = u;
3848c2ecf20Sopenharmony_ci			lasthut = lastlang = lastclass = lastsubclass = -1;
3858c2ecf20Sopenharmony_ci			continue;
3868c2ecf20Sopenharmony_ci		}
3878c2ecf20Sopenharmony_ci		if (buf[0] == '\t' && isxdigit(buf[1])) {
3888c2ecf20Sopenharmony_ci			/* product or subclass spec */
3898c2ecf20Sopenharmony_ci			u = strtoul(buf+1, &cp, 16);
3908c2ecf20Sopenharmony_ci			while (isspace(*cp))
3918c2ecf20Sopenharmony_ci				cp++;
3928c2ecf20Sopenharmony_ci			if (!*cp) {
3938c2ecf20Sopenharmony_ci				err("Invalid product/subclass spec at line %u",
3948c2ecf20Sopenharmony_ci				    linectr);
3958c2ecf20Sopenharmony_ci				continue;
3968c2ecf20Sopenharmony_ci			}
3978c2ecf20Sopenharmony_ci			if (lastvendor != -1) {
3988c2ecf20Sopenharmony_ci				if (new_product(cp, lastvendor, u))
3998c2ecf20Sopenharmony_ci					err("Duplicate product spec at line %u product %04x:%04x %s",
4008c2ecf20Sopenharmony_ci					    linectr, lastvendor, u, cp);
4018c2ecf20Sopenharmony_ci				dbg("line %5u product %04x:%04x %s", linectr,
4028c2ecf20Sopenharmony_ci				    lastvendor, u, cp);
4038c2ecf20Sopenharmony_ci				continue;
4048c2ecf20Sopenharmony_ci			}
4058c2ecf20Sopenharmony_ci			if (lastclass != -1) {
4068c2ecf20Sopenharmony_ci				if (new_subclass(cp, lastclass, u))
4078c2ecf20Sopenharmony_ci					err("Duplicate subclass spec at line %u class %02x:%02x %s",
4088c2ecf20Sopenharmony_ci					    linectr, lastclass, u, cp);
4098c2ecf20Sopenharmony_ci				dbg("line %5u subclass %02x:%02x %s", linectr,
4108c2ecf20Sopenharmony_ci				    lastclass, u, cp);
4118c2ecf20Sopenharmony_ci				lastsubclass = u;
4128c2ecf20Sopenharmony_ci				continue;
4138c2ecf20Sopenharmony_ci			}
4148c2ecf20Sopenharmony_ci			if (lasthut != -1) {
4158c2ecf20Sopenharmony_ci				/* do not store hut */
4168c2ecf20Sopenharmony_ci				continue;
4178c2ecf20Sopenharmony_ci			}
4188c2ecf20Sopenharmony_ci			if (lastlang != -1) {
4198c2ecf20Sopenharmony_ci				/* do not store langid */
4208c2ecf20Sopenharmony_ci				continue;
4218c2ecf20Sopenharmony_ci			}
4228c2ecf20Sopenharmony_ci			err("Product/Subclass spec without prior Vendor/Class spec at line %u",
4238c2ecf20Sopenharmony_ci			    linectr);
4248c2ecf20Sopenharmony_ci			continue;
4258c2ecf20Sopenharmony_ci		}
4268c2ecf20Sopenharmony_ci		if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) {
4278c2ecf20Sopenharmony_ci			/* protocol spec */
4288c2ecf20Sopenharmony_ci			u = strtoul(buf+2, &cp, 16);
4298c2ecf20Sopenharmony_ci			while (isspace(*cp))
4308c2ecf20Sopenharmony_ci				cp++;
4318c2ecf20Sopenharmony_ci			if (!*cp) {
4328c2ecf20Sopenharmony_ci				err("Invalid protocol spec at line %u",
4338c2ecf20Sopenharmony_ci				    linectr);
4348c2ecf20Sopenharmony_ci				continue;
4358c2ecf20Sopenharmony_ci			}
4368c2ecf20Sopenharmony_ci			if (lastclass != -1 && lastsubclass != -1) {
4378c2ecf20Sopenharmony_ci				if (new_protocol(cp, lastclass, lastsubclass,
4388c2ecf20Sopenharmony_ci						 u))
4398c2ecf20Sopenharmony_ci					err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s",
4408c2ecf20Sopenharmony_ci					    linectr, lastclass, lastsubclass,
4418c2ecf20Sopenharmony_ci					    u, cp);
4428c2ecf20Sopenharmony_ci				dbg("line %5u protocol %02x:%02x:%02x %s",
4438c2ecf20Sopenharmony_ci				    linectr, lastclass, lastsubclass, u, cp);
4448c2ecf20Sopenharmony_ci				continue;
4458c2ecf20Sopenharmony_ci			}
4468c2ecf20Sopenharmony_ci			err("Protocol spec without prior Class and Subclass spec at line %u",
4478c2ecf20Sopenharmony_ci			    linectr);
4488c2ecf20Sopenharmony_ci			continue;
4498c2ecf20Sopenharmony_ci		}
4508c2ecf20Sopenharmony_ci		if (buf[0] == 'H' && buf[1] == 'I' &&
4518c2ecf20Sopenharmony_ci		    buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') {
4528c2ecf20Sopenharmony_ci			continue;
4538c2ecf20Sopenharmony_ci		}
4548c2ecf20Sopenharmony_ci		if (buf[0] == 'H' && buf[1] == 'U' &&
4558c2ecf20Sopenharmony_ci		    buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') {
4568c2ecf20Sopenharmony_ci			lastlang = lastclass = lastvendor = lastsubclass = -1;
4578c2ecf20Sopenharmony_ci			/*
4588c2ecf20Sopenharmony_ci			 * set 1 as pseudo-id to indicate that the parser is
4598c2ecf20Sopenharmony_ci			 * in a `HUT' section.
4608c2ecf20Sopenharmony_ci			 */
4618c2ecf20Sopenharmony_ci			lasthut = 1;
4628c2ecf20Sopenharmony_ci			continue;
4638c2ecf20Sopenharmony_ci		}
4648c2ecf20Sopenharmony_ci		if (buf[0] == 'R' && buf[1] == ' ')
4658c2ecf20Sopenharmony_ci			continue;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci		if (buf[0] == 'V' && buf[1] == 'T')
4688c2ecf20Sopenharmony_ci			continue;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci		err("Unknown line at line %u", linectr);
4718c2ecf20Sopenharmony_ci	}
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ciint names_init(char *n)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	FILE *f;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	f = fopen(n, "r");
4808c2ecf20Sopenharmony_ci	if (!f)
4818c2ecf20Sopenharmony_ci		return errno;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	parse(f);
4848c2ecf20Sopenharmony_ci	fclose(f);
4858c2ecf20Sopenharmony_ci	return 0;
4868c2ecf20Sopenharmony_ci}
487