| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *      names.c  --  USB name database manipulation routines | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *      Copyright (C) 1999, 2000  Thomas Sailer (sailer@ife.ee.ethz.ch) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *      This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  *      it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  *      the Free Software Foundation; either version 2 of the License, or | 
					
						
							|  |  |  |  *      (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *      This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  *      but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  *      GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *      You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  *      along with this program; if not, write to the Free Software | 
					
						
							|  |  |  |  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:25 +01:00
										 |  |  |  *	Copyright (C) 2005 Takahiro Hirofuchi | 
					
						
							|  |  |  |  *		- names_deinit() is added. | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <sys/types.h>
 | 
					
						
							|  |  |  | #include <sys/stat.h>
 | 
					
						
							|  |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | #include <dirent.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <ctype.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "names.h"
 | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | #include "usbip_common.h"
 | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct vendor { | 
					
						
							|  |  |  | 	struct vendor *next; | 
					
						
							|  |  |  | 	u_int16_t vendorid; | 
					
						
							|  |  |  | 	char name[1]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct product { | 
					
						
							|  |  |  | 	struct product *next; | 
					
						
							|  |  |  | 	u_int16_t vendorid, productid; | 
					
						
							|  |  |  | 	char name[1]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct class { | 
					
						
							|  |  |  | 	struct class *next; | 
					
						
							|  |  |  | 	u_int8_t classid; | 
					
						
							|  |  |  | 	char name[1]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct subclass { | 
					
						
							|  |  |  | 	struct subclass *next; | 
					
						
							|  |  |  | 	u_int8_t classid, subclassid; | 
					
						
							|  |  |  | 	char name[1]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct protocol { | 
					
						
							|  |  |  | 	struct protocol *next; | 
					
						
							|  |  |  | 	u_int8_t classid, subclassid, protocolid; | 
					
						
							|  |  |  | 	char name[1]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct genericstrtable { | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:25 +01:00
										 |  |  | 	struct genericstrtable *next; | 
					
						
							|  |  |  | 	unsigned int num; | 
					
						
							|  |  |  | 	char name[1]; | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define HASH1  0x10
 | 
					
						
							|  |  |  | #define HASH2  0x02
 | 
					
						
							|  |  |  | #define HASHSZ 16
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned int hashnum(unsigned int num) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1) | 
					
						
							|  |  |  | 		if (num & mask1) | 
					
						
							|  |  |  | 			num ^= mask2; | 
					
						
							|  |  |  | 	return num & (HASHSZ-1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct vendor *vendors[HASHSZ] = { NULL, }; | 
					
						
							|  |  |  | static struct product *products[HASHSZ] = { NULL, }; | 
					
						
							|  |  |  | static struct class *classes[HASHSZ] = { NULL, }; | 
					
						
							|  |  |  | static struct subclass *subclasses[HASHSZ] = { NULL, }; | 
					
						
							|  |  |  | static struct protocol *protocols[HASHSZ] = { NULL, }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const char *names_vendor(u_int16_t vendorid) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct vendor *v; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	v = vendors[hashnum(vendorid)]; | 
					
						
							|  |  |  | 	for (; v; v = v->next) | 
					
						
							|  |  |  | 		if (v->vendorid == vendorid) | 
					
						
							|  |  |  | 			return v->name; | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const char *names_product(u_int16_t vendorid, u_int16_t productid) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct product *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p = products[hashnum((vendorid << 16) | productid)]; | 
					
						
							|  |  |  | 	for (; p; p = p->next) | 
					
						
							|  |  |  | 		if (p->vendorid == vendorid && p->productid == productid) | 
					
						
							|  |  |  | 			return p->name; | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const char *names_class(u_int8_t classid) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct class *c; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	c = classes[hashnum(classid)]; | 
					
						
							|  |  |  | 	for (; c; c = c->next) | 
					
						
							|  |  |  | 		if (c->classid == classid) | 
					
						
							|  |  |  | 			return c->name; | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const char *names_subclass(u_int8_t classid, u_int8_t subclassid) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct subclass *s; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s = subclasses[hashnum((classid << 8) | subclassid)]; | 
					
						
							|  |  |  | 	for (; s; s = s->next) | 
					
						
							|  |  |  | 		if (s->classid == classid && s->subclassid == subclassid) | 
					
						
							|  |  |  | 			return s->name; | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:29 +01:00
										 |  |  | const char *names_protocol(u_int8_t classid, u_int8_t subclassid, | 
					
						
							|  |  |  | 			   u_int8_t protocolid) | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct protocol *p; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:29 +01:00
										 |  |  | 	p = protocols[hashnum((classid << 16) | (subclassid << 8) | 
					
						
							|  |  |  | 			      | protocolid)]; | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 	for (; p; p = p->next) | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:29 +01:00
										 |  |  | 		if (p->classid == classid && p->subclassid == subclassid && | 
					
						
							|  |  |  | 		    p->protocolid == protocolid) | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 			return p->name; | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* add a cleanup function by takahiro */ | 
					
						
							|  |  |  | struct pool { | 
					
						
							|  |  |  | 	struct pool *next; | 
					
						
							|  |  |  | 	void *mem; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:26 +01:00
										 |  |  | static struct pool *pool_head; | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | static void *my_malloc(size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct pool *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p = calloc(1, sizeof(struct pool)); | 
					
						
							| 
									
										
										
										
											2014-01-28 21:16:46 +01:00
										 |  |  | 	if (!p) | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p->mem = calloc(1, size); | 
					
						
							| 
									
										
										
										
											2014-01-28 21:16:46 +01:00
										 |  |  | 	if (!p->mem) { | 
					
						
							|  |  |  | 		free(p); | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2014-01-28 21:16:46 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	p->next = pool_head; | 
					
						
							|  |  |  | 	pool_head = p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return p->mem; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void names_free(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct pool *pool; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!pool_head) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (pool = pool_head; pool != NULL; ) { | 
					
						
							|  |  |  | 		struct pool *tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (pool->mem) | 
					
						
							|  |  |  | 			free(pool->mem); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		tmp = pool; | 
					
						
							|  |  |  | 		pool = pool->next; | 
					
						
							|  |  |  | 		free(tmp); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int new_vendor(const char *name, u_int16_t vendorid) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct vendor *v; | 
					
						
							|  |  |  | 	unsigned int h = hashnum(vendorid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	v = vendors[h]; | 
					
						
							|  |  |  | 	for (; v; v = v->next) | 
					
						
							|  |  |  | 		if (v->vendorid == vendorid) | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 	v = my_malloc(sizeof(struct vendor) + strlen(name)); | 
					
						
							|  |  |  | 	if (!v) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	strcpy(v->name, name); | 
					
						
							|  |  |  | 	v->vendorid = vendorid; | 
					
						
							|  |  |  | 	v->next = vendors[h]; | 
					
						
							|  |  |  | 	vendors[h] = v; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:29 +01:00
										 |  |  | static int new_product(const char *name, u_int16_t vendorid, | 
					
						
							|  |  |  | 		       u_int16_t productid) | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct product *p; | 
					
						
							|  |  |  | 	unsigned int h = hashnum((vendorid << 16) | productid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p = products[h]; | 
					
						
							|  |  |  | 	for (; p; p = p->next) | 
					
						
							|  |  |  | 		if (p->vendorid == vendorid && p->productid == productid) | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 	p = my_malloc(sizeof(struct product) + strlen(name)); | 
					
						
							|  |  |  | 	if (!p) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	strcpy(p->name, name); | 
					
						
							|  |  |  | 	p->vendorid = vendorid; | 
					
						
							|  |  |  | 	p->productid = productid; | 
					
						
							|  |  |  | 	p->next = products[h]; | 
					
						
							|  |  |  | 	products[h] = p; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int new_class(const char *name, u_int8_t classid) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct class *c; | 
					
						
							|  |  |  | 	unsigned int h = hashnum(classid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	c = classes[h]; | 
					
						
							|  |  |  | 	for (; c; c = c->next) | 
					
						
							|  |  |  | 		if (c->classid == classid) | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 	c = my_malloc(sizeof(struct class) + strlen(name)); | 
					
						
							|  |  |  | 	if (!c) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	strcpy(c->name, name); | 
					
						
							|  |  |  | 	c->classid = classid; | 
					
						
							|  |  |  | 	c->next = classes[h]; | 
					
						
							|  |  |  | 	classes[h] = c; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct subclass *s; | 
					
						
							|  |  |  | 	unsigned int h = hashnum((classid << 8) | subclassid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s = subclasses[h]; | 
					
						
							|  |  |  | 	for (; s; s = s->next) | 
					
						
							|  |  |  | 		if (s->classid == classid && s->subclassid == subclassid) | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 	s = my_malloc(sizeof(struct subclass) + strlen(name)); | 
					
						
							|  |  |  | 	if (!s) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	strcpy(s->name, name); | 
					
						
							|  |  |  | 	s->classid = classid; | 
					
						
							|  |  |  | 	s->subclassid = subclassid; | 
					
						
							|  |  |  | 	s->next = subclasses[h]; | 
					
						
							|  |  |  | 	subclasses[h] = s; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:29 +01:00
										 |  |  | static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid, | 
					
						
							|  |  |  | 			u_int8_t protocolid) | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct protocol *p; | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:29 +01:00
										 |  |  | 	unsigned int h = hashnum((classid << 16) | (subclassid << 8) | 
					
						
							|  |  |  | 				 | protocolid); | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	p = protocols[h]; | 
					
						
							|  |  |  | 	for (; p; p = p->next) | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:29 +01:00
										 |  |  | 		if (p->classid == classid && p->subclassid == subclassid | 
					
						
							|  |  |  | 		    && p->protocolid == protocolid) | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 			return -1; | 
					
						
							|  |  |  | 	p = my_malloc(sizeof(struct protocol) + strlen(name)); | 
					
						
							|  |  |  | 	if (!p) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	strcpy(p->name, name); | 
					
						
							|  |  |  | 	p->classid = classid; | 
					
						
							|  |  |  | 	p->subclassid = subclassid; | 
					
						
							|  |  |  | 	p->protocolid = protocolid; | 
					
						
							|  |  |  | 	p->next = protocols[h]; | 
					
						
							|  |  |  | 	protocols[h] = p; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void parse(FILE *f) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char buf[512], *cp; | 
					
						
							|  |  |  | 	unsigned int linectr = 0; | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:29 +01:00
										 |  |  | 	int lastvendor = -1; | 
					
						
							|  |  |  | 	int lastclass = -1; | 
					
						
							|  |  |  | 	int lastsubclass = -1; | 
					
						
							|  |  |  | 	int lasthut = -1; | 
					
						
							|  |  |  | 	int lastlang = -1; | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 	unsigned int u; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (fgets(buf, sizeof(buf), f)) { | 
					
						
							|  |  |  | 		linectr++; | 
					
						
							|  |  |  | 		/* remove line ends */ | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:02 +02:00
										 |  |  | 		cp = strchr(buf, '\r'); | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:30 +01:00
										 |  |  | 		if (cp) | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 			*cp = 0; | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:02 +02:00
										 |  |  | 		cp = strchr(buf, '\n'); | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:30 +01:00
										 |  |  | 		if (cp) | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 			*cp = 0; | 
					
						
							|  |  |  | 		if (buf[0] == '#' || !buf[0]) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		cp = buf; | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 		if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && | 
					
						
							|  |  |  | 		    buf[3] == 'S' && buf[4] == 'D' && | 
					
						
							|  |  |  | 		    buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/ | 
					
						
							|  |  |  | 		    buf[7] == ' ') { | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:25 +01:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 		if (buf[0] == 'P' && buf[1] == 'H' && | 
					
						
							|  |  |  | 		    buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') { | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:25 +01:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 		if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' && | 
					
						
							|  |  |  | 		    buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') { | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:25 +01:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') { | 
					
						
							|  |  |  | 			lasthut = lastclass = lastvendor = lastsubclass = -1; | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * set 1 as pseudo-id to indicate that the parser is | 
					
						
							|  |  |  | 			 * in a `L' section. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			lastlang = 1; | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:25 +01:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 		if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') { | 
					
						
							|  |  |  | 			/* class spec */ | 
					
						
							|  |  |  | 			cp = buf+2; | 
					
						
							|  |  |  | 			while (isspace(*cp)) | 
					
						
							|  |  |  | 				cp++; | 
					
						
							|  |  |  | 			if (!isxdigit(*cp)) { | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 				err("Invalid class spec at line %u", linectr); | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			u = strtoul(cp, &cp, 16); | 
					
						
							|  |  |  | 			while (isspace(*cp)) | 
					
						
							|  |  |  | 				cp++; | 
					
						
							|  |  |  | 			if (!*cp) { | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 				err("Invalid class spec at line %u", linectr); | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (new_class(cp, u)) | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 				err("Duplicate class spec at line %u class %04x %s", | 
					
						
							|  |  |  | 				    linectr, u, cp); | 
					
						
							|  |  |  | 			dbg("line %5u class %02x %s", linectr, u, cp); | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 			lasthut = lastlang = lastvendor = lastsubclass = -1; | 
					
						
							|  |  |  | 			lastclass = u; | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) { | 
					
						
							|  |  |  | 			/* audio terminal type spec */ | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:29 +01:00
										 |  |  | 		if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C' | 
					
						
							|  |  |  | 		    && isspace(buf[3])) { | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 			/* HID Descriptor bCountryCode */ | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:25 +01:00
										 |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (isxdigit(*cp)) { | 
					
						
							|  |  |  | 			/* vendor */ | 
					
						
							|  |  |  | 			u = strtoul(cp, &cp, 16); | 
					
						
							|  |  |  | 			while (isspace(*cp)) | 
					
						
							|  |  |  | 				cp++; | 
					
						
							|  |  |  | 			if (!*cp) { | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 				err("Invalid vendor spec at line %u", linectr); | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (new_vendor(cp, u)) | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 				err("Duplicate vendor spec at line %u vendor %04x %s", | 
					
						
							|  |  |  | 				    linectr, u, cp); | 
					
						
							|  |  |  | 			dbg("line %5u vendor %04x %s", linectr, u, cp); | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 			lastvendor = u; | 
					
						
							|  |  |  | 			lasthut = lastlang = lastclass = lastsubclass = -1; | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (buf[0] == '\t' && isxdigit(buf[1])) { | 
					
						
							|  |  |  | 			/* product or subclass spec */ | 
					
						
							|  |  |  | 			u = strtoul(buf+1, &cp, 16); | 
					
						
							|  |  |  | 			while (isspace(*cp)) | 
					
						
							|  |  |  | 				cp++; | 
					
						
							|  |  |  | 			if (!*cp) { | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 				err("Invalid product/subclass spec at line %u", | 
					
						
							|  |  |  | 				    linectr); | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (lastvendor != -1) { | 
					
						
							|  |  |  | 				if (new_product(cp, lastvendor, u)) | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 					err("Duplicate product spec at line %u product %04x:%04x %s", | 
					
						
							|  |  |  | 					    linectr, lastvendor, u, cp); | 
					
						
							|  |  |  | 				dbg("line %5u product %04x:%04x %s", linectr, | 
					
						
							|  |  |  | 				    lastvendor, u, cp); | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (lastclass != -1) { | 
					
						
							|  |  |  | 				if (new_subclass(cp, lastclass, u)) | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 					err("Duplicate subclass spec at line %u class %02x:%02x %s", | 
					
						
							|  |  |  | 					    linectr, lastclass, u, cp); | 
					
						
							|  |  |  | 				dbg("line %5u subclass %02x:%02x %s", linectr, | 
					
						
							|  |  |  | 				    lastclass, u, cp); | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 				lastsubclass = u; | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (lasthut != -1) { | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 				/* do not store hut */ | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (lastlang != -1) { | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 				/* do not store langid */ | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:25 +01:00
										 |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 			err("Product/Subclass spec without prior Vendor/Class spec at line %u", | 
					
						
							|  |  |  | 			    linectr); | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) { | 
					
						
							|  |  |  | 			/* protocol spec */ | 
					
						
							|  |  |  | 			u = strtoul(buf+2, &cp, 16); | 
					
						
							|  |  |  | 			while (isspace(*cp)) | 
					
						
							|  |  |  | 				cp++; | 
					
						
							|  |  |  | 			if (!*cp) { | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 				err("Invalid protocol spec at line %u", | 
					
						
							|  |  |  | 				    linectr); | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (lastclass != -1 && lastsubclass != -1) { | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 				if (new_protocol(cp, lastclass, lastsubclass, | 
					
						
							|  |  |  | 						 u)) | 
					
						
							|  |  |  | 					err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s", | 
					
						
							|  |  |  | 					    linectr, lastclass, lastsubclass, | 
					
						
							|  |  |  | 					    u, cp); | 
					
						
							|  |  |  | 				dbg("line %5u protocol %02x:%02x:%02x %s", | 
					
						
							|  |  |  | 				    linectr, lastclass, lastsubclass, u, cp); | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 			err("Protocol spec without prior Class and Subclass spec at line %u", | 
					
						
							|  |  |  | 			    linectr); | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 		if (buf[0] == 'H' && buf[1] == 'I' && | 
					
						
							|  |  |  | 		    buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') { | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:25 +01:00
										 |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 		if (buf[0] == 'H' && buf[1] == 'U' && | 
					
						
							|  |  |  | 		    buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') { | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 			lastlang = lastclass = lastvendor = lastsubclass = -1; | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * set 1 as pseudo-id to indicate that the parser is | 
					
						
							|  |  |  | 			 * in a `HUT' section. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			lasthut = 1; | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:25 +01:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 		if (buf[0] == 'R' && buf[1] == ' ') | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:25 +01:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 		if (buf[0] == 'V' && buf[1] == 'T') | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2013-04-04 16:03:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		err("Unknown line at line %u", linectr); | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int names_init(char *n) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	FILE *f; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:30 +01:00
										 |  |  | 	f = fopen(n, "r"); | 
					
						
							|  |  |  | 	if (!f) | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 		return errno; | 
					
						
							| 
									
										
										
										
											2013-02-22 12:13:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-14 03:55:07 -07:00
										 |  |  | 	parse(f); | 
					
						
							|  |  |  | 	fclose(f); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } |