1/*
2 * names.c		db names
3 *
4 *		This program is free software; you can redistribute it and/or
5 *		modify it under the terms of the GNU General Public License
6 *		as published by the Free Software Foundation; either version
7 *		2 of the License, or (at your option) any later version.
8 *
9 */
10
11#include <stdio.h>
12#include <string.h>
13#include <stdlib.h>
14#include <errno.h>
15
16#include "names.h"
17#include "utils.h"
18
19#define MAX_ENTRIES  256
20#define NAME_MAX_LEN 512
21
22static int read_id_name(FILE *fp, int *id, char *name)
23{
24	char buf[NAME_MAX_LEN];
25	int min, maj;
26
27	while (fgets(buf, sizeof(buf), fp)) {
28		char *p = buf;
29
30		while (*p == ' ' || *p == '\t')
31			p++;
32
33		if (*p == '#' || *p == '\n' || *p == 0)
34			continue;
35
36		if (sscanf(p, "%x:%x %s\n", &maj, &min, name) == 3) {
37			*id = (maj << 16) | min;
38		} else if (sscanf(p, "%x:%x %s #", &maj, &min, name) == 3) {
39			*id = (maj << 16) | min;
40		} else if (sscanf(p, "0x%x %s\n", id, name) != 2 &&
41				sscanf(p, "0x%x %s #", id, name) != 2 &&
42				sscanf(p, "%d %s\n", id, name) != 2 &&
43				sscanf(p, "%d %s #", id, name) != 2) {
44			strcpy(name, p);
45			return -1;
46		}
47		return 1;
48	}
49
50	return 0;
51}
52
53struct db_names *db_names_alloc(void)
54{
55	struct db_names *db;
56
57	db = calloc(1, sizeof(*db));
58	if (!db)
59		return NULL;
60
61	db->size = MAX_ENTRIES;
62	db->hash = calloc(db->size, sizeof(struct db_entry *));
63
64	return db;
65}
66
67int db_names_load(struct db_names *db, const char *path)
68{
69	struct db_entry *entry;
70	FILE *fp;
71	int id;
72	char namebuf[NAME_MAX_LEN] = {0};
73	int ret = -1;
74
75	fp = fopen(path, "r");
76	if (!fp)
77		return -ENOENT;
78
79	while ((ret = read_id_name(fp, &id, &namebuf[0]))) {
80		if (ret == -1) {
81			fprintf(stderr, "Database %s is corrupted at %s\n",
82					path, namebuf);
83			goto Exit;
84		}
85		ret = -1;
86
87		if (id < 0)
88			continue;
89
90		entry = malloc(sizeof(*entry));
91		if (!entry)
92			goto Exit;
93
94		entry->name = strdup(namebuf);
95		if (!entry->name) {
96			free(entry);
97			goto Exit;
98		}
99
100		entry->id   = id;
101		entry->next = db->hash[id & (db->size - 1)];
102		db->hash[id & (db->size - 1)] = entry;
103	}
104	ret = 0;
105
106Exit:
107	fclose(fp);
108	return ret;
109}
110
111void db_names_free(struct db_names *db)
112{
113	int i;
114
115	if (!db)
116		return;
117
118	for (i = 0; i < db->size; i++) {
119		struct db_entry *entry = db->hash[i];
120
121		while (entry) {
122			struct db_entry *next = entry->next;
123
124			free(entry->name);
125			free(entry);
126			entry = next;
127		}
128	}
129
130	free(db->hash);
131	free(db);
132}
133
134char *id_to_name(struct db_names *db, int id, char *name)
135{
136	struct db_entry *entry;
137
138	if (!db)
139		return NULL;
140
141	entry = db->hash[id & (db->size - 1)];
142	while (entry && entry->id != id)
143		entry = entry->next;
144
145	if (entry) {
146		strncpy(name, entry->name, IDNAME_MAX);
147		return name;
148	}
149
150	snprintf(name, IDNAME_MAX, "%d", id);
151	return NULL;
152}
153
154int name_to_id(struct db_names *db, int *id, const char *name)
155{
156	struct db_entry *entry;
157	int i;
158
159	if (!db)
160		return -1;
161
162	if (db->cached && strcmp(db->cached->name, name) == 0) {
163		*id = db->cached->id;
164		return 0;
165	}
166
167	for (i = 0; i < db->size; i++) {
168		entry = db->hash[i];
169		while (entry && strcmp(entry->name, name))
170			entry = entry->next;
171
172		if (entry) {
173			db->cached = entry;
174			*id = entry->id;
175			return 0;
176		}
177	}
178
179	return -1;
180}
181