opkg: (leak fixing, day 1) lots and lots of memory leaks fixed
[project/opkg-lede.git] / libopkg / hash_table.c
1 /* hash.c - hash tables for opkg
2
3 Steven M. Ayer, Jamey Hicks
4
5 Copyright (C) 2002 Compaq Computer Corporation
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2, or (at
10 your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16 */
17
18 #include <errno.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include "hash_table.h"
23 #include "opkg_message.h"
24
25
26 static int hash_index(hash_table_t *hash, const char *pkg_name);
27 static int rotating(const char *key, int len, int prime);
28
29 static int hash_index(hash_table_t *hash, const char *pkg_name)
30 {
31 return rotating(pkg_name, strlen(pkg_name), hash->n_entries);
32 }
33
34 static int rotating(const char *key, int len, int prime)
35 {
36 unsigned int hash, i;
37 for (hash=len, i=0; i<len; ++i)
38 hash = (hash<<4)^(hash>>28)^key[i];
39 return (hash % prime);
40 }
41
42
43 /*
44 * this is an open table keyed by strings
45 */
46 int hash_table_init(const char *name, hash_table_t *hash, int len)
47 {
48 static int primes_table[] = {
49 379, 761, 983, 1423, 2711, 3361, 3931, 4679, 5519, 6701, 9587,
50 19471, 23143, 33961, 46499, 49727, 99529, 0
51 };
52 int *picker;
53
54 if (hash->entries != NULL) {
55 /* we have been here already */
56 return 0;
57 }
58
59 hash->name = name;
60 hash->entries = NULL;
61 hash->n_entries = 0;
62 hash->hash_entry_key = NULL;
63
64 picker = primes_table;
65 while(*picker && (*picker++ < len));
66 if(!*picker)
67 fprintf(stderr, "%s: primes table might not be big enough (! << %d)\n", __FUNCTION__, len);
68 --picker;
69
70 hash->n_entries = *picker;
71 hash->entries = (hash_entry_t *)calloc(hash->n_entries, sizeof(hash_entry_t));
72 if (hash->entries == NULL) {
73 fprintf(stderr, "%s: Out of memory.\n", __FUNCTION__);
74 return ENOMEM;
75 }
76 return 0;
77 }
78
79 void hash_table_deinit(hash_table_t *hash)
80 {
81 int i;
82 if (!hash)
83 return;
84
85 /* free the reminaing entries */
86 for (i = 0; i < hash->n_entries; i++) {
87 hash_entry_t *hash_entry = (hash->entries + i);
88 /* skip the first entry as this is part of the array */
89 hash_entry = hash_entry->next;
90 while (hash_entry)
91 {
92 hash_entry_t *old = hash_entry;
93 hash_entry = hash_entry->next;
94 free (old->key);
95 free (old);
96 }
97 }
98
99 free (hash->entries);
100
101 hash->entries = NULL;
102 hash->n_entries = 0;
103 }
104
105 void *hash_table_get(hash_table_t *hash, const char *key)
106 {
107 int ndx= hash_index(hash, key);
108 hash_entry_t *hash_entry = hash->entries + ndx;
109 while (hash_entry)
110 {
111 if (hash_entry->key)
112 {
113 if (strcmp(key, hash_entry->key) == 0) {
114 // opkg_message(NULL, OPKG_DEBUG, "Function: %s. Key found for '%s' \n", __FUNCTION__, key);
115 return hash_entry->data;
116 }
117 }
118 hash_entry = hash_entry->next;
119 }
120 return NULL;
121 }
122
123 int hash_table_insert(hash_table_t *hash, const char *key, void *value)
124 {
125 int ndx= hash_index(hash, key);
126 hash_entry_t *hash_entry = hash->entries + ndx;
127 if (0) opkg_message(NULL, OPKG_DEBUG2, "Function: %s. Inserting in hash for '%s' \n", __FUNCTION__, key);
128 if (hash_entry->key) {
129 if (strcmp(hash_entry->key, key) == 0) {
130 /* alread in table, update the value */
131 if (0) opkg_message(NULL, OPKG_DEBUG2, "Function: %s. Value already in hash for '%s' \n", __FUNCTION__, key);
132 hash_entry->data = value;
133 return 0;
134 } else {
135 /*
136 * if this is a collision, we have to go to the end of the ll,
137 * then add a new entry
138 * before we can hook up the value
139 */
140 if (0) opkg_message(NULL, OPKG_DEBUG2, "Function: %s. Value already in hash by collision for '%s' \n", __FUNCTION__, key);
141 while (hash_entry->next)
142 hash_entry = hash_entry->next;
143 hash_entry->next = (hash_entry_t *)malloc(sizeof(hash_entry_t));
144 if (!hash_entry->next) {
145 return -ENOMEM;
146 }
147 hash_entry = hash_entry->next;
148 hash_entry->next = NULL;
149 }
150 }
151 hash->n_elements++;
152 hash_entry->key = strdup(key);
153 hash_entry->data = value;
154
155 return 0;
156 }
157
158
159 void hash_table_foreach(hash_table_t *hash, void (*f)(const char *key, void *entry, void *data), void *data)
160 {
161 int i;
162 if (!hash || !f)
163 return;
164
165 for (i = 0; i < hash->n_entries; i++) {
166 hash_entry_t *hash_entry = (hash->entries + i);
167 do {
168 if(hash_entry->key) {
169 f(hash_entry->key, hash_entry->data, data);
170 }
171 } while((hash_entry = hash_entry->next));
172 }
173 }
174