1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <synch.h>
29 #include <memory.h>
30 #include "hash.h"
31 
32 static int    hash_string(const char *, long);
33 
34 hash *
make_hash(size_t size)35 make_hash(size_t size)
36 {
37 	hash	*ptr;
38 
39 	ptr = malloc(sizeof (*ptr));
40 	ptr->size = size;
41 	ptr->table = malloc((size_t)(sizeof (hash_entry *) * size));
42 	(void) memset((char *)ptr->table, 0, sizeof (hash_entry *) * size);
43 	ptr->start = NULL;
44 	ptr->hash_type = String_Key;
45 	return (ptr);
46 }
47 
48 hash *
make_ihash(size_t size)49 make_ihash(size_t size)
50 {
51 	hash	*ptr;
52 
53 	ptr = malloc(sizeof (*ptr));
54 	ptr->size = size;
55 	ptr->table = malloc(sizeof (hash_entry *) * size);
56 	(void) memset((char *)ptr->table, 0, sizeof (hash_entry *) * size);
57 	ptr->start = NULL;
58 	ptr->hash_type = Integer_Key;
59 	return (ptr);
60 }
61 
62 char **
get_hash(hash * tbl,char * key)63 get_hash(hash *tbl, char *key)
64 {
65 	long		bucket;
66 	hash_entry	*tmp, *new;
67 
68 	if (tbl->hash_type == String_Key) {
69 		tmp = tbl->table[bucket = hash_string(key, tbl->size)];
70 	} else {
71 		tmp = tbl->table[bucket = labs((long)key) % tbl->size];
72 	}
73 
74 	if (tbl->hash_type == String_Key) {
75 		while (tmp != NULL) {
76 			if (strcmp(tmp->key, key) == 0) {
77 				return (&tmp->data);
78 			}
79 			tmp = tmp->next_entry;
80 		}
81 	} else {
82 		while (tmp != NULL) {
83 			if (tmp->key == key) {
84 				return (&tmp->data);
85 			}
86 			tmp = tmp->next_entry;
87 		}
88 	}
89 
90 	/*
91 	 * not found....
92 	 * insert new entry into bucket...
93 	 */
94 	new = malloc(sizeof (*new));
95 	new->key = ((tbl->hash_type == String_Key)?strdup(key):key);
96 
97 	/*
98 	 * hook into chain from tbl...
99 	 */
100 	new->right_entry = NULL;
101 	new->left_entry = tbl->start;
102 	tbl->start = new;
103 
104 	/*
105 	 * hook into bucket chain
106 	 */
107 	new->next_entry = tbl->table[bucket];
108 	tbl->table[bucket] = new;
109 	new->data = NULL;		/* so we know that it is new */
110 	return (&new->data);
111 }
112 
113 char **
find_hash(hash * tbl,const char * key)114 find_hash(hash *tbl, const char *key)
115 {
116 	hash_entry 	*tmp;
117 
118 	if (tbl->hash_type == String_Key) {
119 		tmp = tbl->table[hash_string(key, tbl->size)];
120 		for (; tmp != NULL; tmp = tmp->next_entry) {
121 			if (strcmp(tmp->key, key) == 0) {
122 				return (&tmp->data);
123 			}
124 		}
125 	} else {
126 		tmp = tbl->table[labs((long)key) % tbl->size];
127 		for (; tmp != NULL; tmp = tmp->next_entry) {
128 			if (tmp->key == key) {
129 				return (&tmp->data);
130 			}
131 		}
132 	}
133 	return (NULL);
134 }
135 
136 char *
del_hash(hash * tbl,const char * key)137 del_hash(hash *tbl, const char *key)
138 {
139 	ulong_t bucket;
140 	hash_entry * tmp, * prev = NULL;
141 
142 	if (tbl->hash_type == String_Key) {
143 		bucket = hash_string(key, tbl->size);
144 	} else {
145 		bucket = labs((long)key) % tbl->size;
146 	}
147 
148 	if ((tmp = tbl->table[bucket]) == NULL) {
149 		return (NULL);
150 	} else {
151 		if (tbl->hash_type == String_Key) {
152 			while (tmp != NULL) {
153 				if (strcmp(tmp->key, key) == 0) {
154 					break;  /* found item to delete ! */
155 				}
156 				prev = tmp;
157 				tmp  = tmp->next_entry;
158 			}
159 		} else {
160 			while (tmp != NULL) {
161 				if (tmp->key == key) {
162 					break;
163 				}
164 				prev = tmp;
165 				tmp  = tmp->next_entry;
166 			}
167 		}
168 		if (tmp == NULL) {
169 			return (NULL); /* not found */
170 		}
171 	}
172 
173 	/*
174 	 * tmp now points to entry marked for deletion, prev to
175 	 * item preceding in bucket chain or NULL if tmp is first.
176 	 * remove from bucket chain first....
177 	 */
178 	if (tbl->hash_type == String_Key) {
179 		free(tmp->key);
180 	}
181 	if (prev != NULL) {
182 		prev->next_entry = tmp->next_entry;
183 	} else {
184 		tbl->table[bucket] = tmp->next_entry;
185 	}
186 
187 	/*
188 	 * now remove from tbl chain....
189 	 */
190 	if (tmp->right_entry != NULL) { /* not first in chain.... */
191 		tmp->right_entry->left_entry = (tmp->left_entry ?
192 		    tmp->left_entry->right_entry: NULL);
193 	} else {
194 		tbl->start = (tmp->left_entry ?tmp->left_entry->right_entry:
195 		    NULL);
196 	}
197 	return (tmp->data);
198 }
199 
200 size_t
operate_hash(hash * tbl,void (* ptr)(),const char * usr_arg)201 operate_hash(hash *tbl, void (*ptr)(), const char *usr_arg)
202 {
203 	hash_entry	*tmp = tbl->start;
204 	size_t		c = 0;
205 
206 	while (tmp) {
207 		(*ptr)(tmp->data, usr_arg, tmp->key);
208 		tmp = tmp->left_entry;
209 		c++;
210 	}
211 	return (c);
212 }
213 
214 size_t
operate_hash_addr(hash * tbl,void (* ptr)(),const char * usr_arg)215 operate_hash_addr(hash *tbl, void (*ptr)(), const char *usr_arg)
216 {
217 	hash_entry	*tmp = tbl->start;
218 	size_t		c = 0;
219 
220 	while (tmp) {
221 		(*ptr)(&(tmp->data), usr_arg, tmp->key);
222 		tmp = tmp->left_entry;
223 		c++;
224 	}
225 	return (c);
226 }
227 
228 void
destroy_hash(hash * tbl,int (* ptr)(),const char * usr_arg)229 destroy_hash(hash *tbl, int (*ptr)(), const char *usr_arg)
230 {
231 	hash_entry * tmp = tbl->start, * prev;
232 
233 	while (tmp) {
234 		if (ptr) {
235 			(void) (*ptr)(tmp->data, usr_arg, tmp->key);
236 		}
237 
238 		if (tbl->hash_type == String_Key) {
239 			free(tmp->key);
240 		}
241 		prev = tmp;
242 		tmp = tmp->left_entry;
243 		free((char *)prev);
244 	}
245 	free((char *)tbl->table);
246 	free(tbl);
247 }
248 
249 static int
hash_string(const char * s,long modulo)250 hash_string(const char *s, long modulo)
251 {
252 	unsigned int	result = 0;
253 	int		i = 1;
254 
255 	while (*s != '\0') {
256 		result += (*s++ << i++);
257 	}
258 
259 	/* LINTED */
260 	return ((int)(result % modulo));
261 }
262