xref: /onnv-gate/usr/src/cmd/sgs/link_audit/common/hash.c (revision 12927:a27c46eb192b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*12927SRod.Evans@Sun.COM  * Common Development and Distribution License (the "License").
6*12927SRod.Evans@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*12927SRod.Evans@Sun.COM 
220Sstevel@tonic-gate /*
23*12927SRod.Evans@Sun.COM  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate #include <stdio.h>
260Sstevel@tonic-gate #include <stdlib.h>
270Sstevel@tonic-gate #include <string.h>
280Sstevel@tonic-gate #include <synch.h>
290Sstevel@tonic-gate #include <memory.h>
300Sstevel@tonic-gate #include "hash.h"
310Sstevel@tonic-gate 
320Sstevel@tonic-gate static int    hash_string(const char *, long);
330Sstevel@tonic-gate 
340Sstevel@tonic-gate hash *
make_hash(size_t size)350Sstevel@tonic-gate make_hash(size_t size)
360Sstevel@tonic-gate {
37*12927SRod.Evans@Sun.COM 	hash	*ptr;
380Sstevel@tonic-gate 
39*12927SRod.Evans@Sun.COM 	ptr = malloc(sizeof (*ptr));
400Sstevel@tonic-gate 	ptr->size = size;
41*12927SRod.Evans@Sun.COM 	ptr->table = malloc((size_t)(sizeof (hash_entry *) * size));
42*12927SRod.Evans@Sun.COM 	(void) memset((char *)ptr->table, 0, sizeof (hash_entry *) * size);
430Sstevel@tonic-gate 	ptr->start = NULL;
440Sstevel@tonic-gate 	ptr->hash_type = String_Key;
450Sstevel@tonic-gate 	return (ptr);
460Sstevel@tonic-gate }
470Sstevel@tonic-gate 
480Sstevel@tonic-gate hash *
make_ihash(size_t size)490Sstevel@tonic-gate make_ihash(size_t size)
500Sstevel@tonic-gate {
51*12927SRod.Evans@Sun.COM 	hash	*ptr;
520Sstevel@tonic-gate 
53*12927SRod.Evans@Sun.COM 	ptr = malloc(sizeof (*ptr));
540Sstevel@tonic-gate 	ptr->size = size;
55*12927SRod.Evans@Sun.COM 	ptr->table = malloc(sizeof (hash_entry *) * size);
56*12927SRod.Evans@Sun.COM 	(void) memset((char *)ptr->table, 0, sizeof (hash_entry *) * size);
570Sstevel@tonic-gate 	ptr->start = NULL;
580Sstevel@tonic-gate 	ptr->hash_type = Integer_Key;
590Sstevel@tonic-gate 	return (ptr);
600Sstevel@tonic-gate }
610Sstevel@tonic-gate 
620Sstevel@tonic-gate char **
get_hash(hash * tbl,char * key)630Sstevel@tonic-gate get_hash(hash *tbl, char *key)
640Sstevel@tonic-gate {
65*12927SRod.Evans@Sun.COM 	long		bucket;
66*12927SRod.Evans@Sun.COM 	hash_entry	*tmp, *new;
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 	if (tbl->hash_type == String_Key) {
690Sstevel@tonic-gate 		tmp = tbl->table[bucket = hash_string(key, tbl->size)];
700Sstevel@tonic-gate 	} else {
710Sstevel@tonic-gate 		tmp = tbl->table[bucket = labs((long)key) % tbl->size];
720Sstevel@tonic-gate 	}
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 	if (tbl->hash_type == String_Key) {
750Sstevel@tonic-gate 		while (tmp != NULL) {
760Sstevel@tonic-gate 			if (strcmp(tmp->key, key) == 0) {
770Sstevel@tonic-gate 				return (&tmp->data);
780Sstevel@tonic-gate 			}
790Sstevel@tonic-gate 			tmp = tmp->next_entry;
800Sstevel@tonic-gate 		}
810Sstevel@tonic-gate 	} else {
820Sstevel@tonic-gate 		while (tmp != NULL) {
830Sstevel@tonic-gate 			if (tmp->key == key) {
840Sstevel@tonic-gate 				return (&tmp->data);
850Sstevel@tonic-gate 			}
860Sstevel@tonic-gate 			tmp = tmp->next_entry;
870Sstevel@tonic-gate 		}
880Sstevel@tonic-gate 	}
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	/*
910Sstevel@tonic-gate 	 * not found....
920Sstevel@tonic-gate 	 * insert new entry into bucket...
930Sstevel@tonic-gate 	 */
94*12927SRod.Evans@Sun.COM 	new = malloc(sizeof (*new));
95*12927SRod.Evans@Sun.COM 	new->key = ((tbl->hash_type == String_Key)?strdup(key):key);
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	/*
980Sstevel@tonic-gate 	 * hook into chain from tbl...
990Sstevel@tonic-gate 	 */
1000Sstevel@tonic-gate 	new->right_entry = NULL;
1010Sstevel@tonic-gate 	new->left_entry = tbl->start;
1020Sstevel@tonic-gate 	tbl->start = new;
103*12927SRod.Evans@Sun.COM 
1040Sstevel@tonic-gate 	/*
1050Sstevel@tonic-gate 	 * hook into bucket chain
1060Sstevel@tonic-gate 	 */
1070Sstevel@tonic-gate 	new->next_entry = tbl->table[bucket];
1080Sstevel@tonic-gate 	tbl->table[bucket] = new;
109*12927SRod.Evans@Sun.COM 	new->data = NULL;		/* so we know that it is new */
1100Sstevel@tonic-gate 	return (&new->data);
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate char **
find_hash(hash * tbl,const char * key)1140Sstevel@tonic-gate find_hash(hash *tbl, const char *key)
1150Sstevel@tonic-gate {
1160Sstevel@tonic-gate 	hash_entry 	*tmp;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	if (tbl->hash_type == String_Key) {
1190Sstevel@tonic-gate 		tmp = tbl->table[hash_string(key, tbl->size)];
1200Sstevel@tonic-gate 		for (; tmp != NULL; tmp = tmp->next_entry) {
1210Sstevel@tonic-gate 			if (strcmp(tmp->key, key) == 0) {
1220Sstevel@tonic-gate 				return (&tmp->data);
1230Sstevel@tonic-gate 			}
1240Sstevel@tonic-gate 		}
1250Sstevel@tonic-gate 	} else {
1260Sstevel@tonic-gate 		tmp = tbl->table[labs((long)key) % tbl->size];
1270Sstevel@tonic-gate 		for (; tmp != NULL; tmp = tmp->next_entry) {
1280Sstevel@tonic-gate 			if (tmp->key == key) {
1290Sstevel@tonic-gate 				return (&tmp->data);
1300Sstevel@tonic-gate 			}
1310Sstevel@tonic-gate 		}
1320Sstevel@tonic-gate 	}
1330Sstevel@tonic-gate 	return (NULL);
1340Sstevel@tonic-gate }
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate char *
del_hash(hash * tbl,const char * key)1370Sstevel@tonic-gate del_hash(hash *tbl, const char *key)
1380Sstevel@tonic-gate {
1390Sstevel@tonic-gate 	ulong_t bucket;
1400Sstevel@tonic-gate 	hash_entry * tmp, * prev = NULL;
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	if (tbl->hash_type == String_Key) {
1430Sstevel@tonic-gate 		bucket = hash_string(key, tbl->size);
1440Sstevel@tonic-gate 	} else {
1450Sstevel@tonic-gate 		bucket = labs((long)key) % tbl->size;
1460Sstevel@tonic-gate 	}
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	if ((tmp = tbl->table[bucket]) == NULL) {
1490Sstevel@tonic-gate 		return (NULL);
1500Sstevel@tonic-gate 	} else {
1510Sstevel@tonic-gate 		if (tbl->hash_type == String_Key) {
1520Sstevel@tonic-gate 			while (tmp != NULL) {
1530Sstevel@tonic-gate 				if (strcmp(tmp->key, key) == 0) {
1540Sstevel@tonic-gate 					break;  /* found item to delete ! */
1550Sstevel@tonic-gate 				}
1560Sstevel@tonic-gate 				prev = tmp;
1570Sstevel@tonic-gate 				tmp  = tmp->next_entry;
1580Sstevel@tonic-gate 			}
1590Sstevel@tonic-gate 		} else {
1600Sstevel@tonic-gate 			while (tmp != NULL) {
1610Sstevel@tonic-gate 				if (tmp->key == key) {
1620Sstevel@tonic-gate 					break;
1630Sstevel@tonic-gate 				}
1640Sstevel@tonic-gate 				prev = tmp;
1650Sstevel@tonic-gate 				tmp  = tmp->next_entry;
1660Sstevel@tonic-gate 			}
1670Sstevel@tonic-gate 		}
1680Sstevel@tonic-gate 		if (tmp == NULL) {
1690Sstevel@tonic-gate 			return (NULL); /* not found */
1700Sstevel@tonic-gate 		}
1710Sstevel@tonic-gate 	}
172*12927SRod.Evans@Sun.COM 
1730Sstevel@tonic-gate 	/*
1740Sstevel@tonic-gate 	 * tmp now points to entry marked for deletion, prev to
175*12927SRod.Evans@Sun.COM 	 * item preceding in bucket chain or NULL if tmp is first.
1760Sstevel@tonic-gate 	 * remove from bucket chain first....
1770Sstevel@tonic-gate 	 */
1780Sstevel@tonic-gate 	if (tbl->hash_type == String_Key) {
1790Sstevel@tonic-gate 		free(tmp->key);
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 	if (prev != NULL) {
1820Sstevel@tonic-gate 		prev->next_entry = tmp->next_entry;
1830Sstevel@tonic-gate 	} else {
1840Sstevel@tonic-gate 		tbl->table[bucket] = tmp->next_entry;
1850Sstevel@tonic-gate 	}
186*12927SRod.Evans@Sun.COM 
1870Sstevel@tonic-gate 	/*
1880Sstevel@tonic-gate 	 * now remove from tbl chain....
1890Sstevel@tonic-gate 	 */
1900Sstevel@tonic-gate 	if (tmp->right_entry != NULL) { /* not first in chain.... */
1910Sstevel@tonic-gate 		tmp->right_entry->left_entry = (tmp->left_entry ?
1920Sstevel@tonic-gate 		    tmp->left_entry->right_entry: NULL);
1930Sstevel@tonic-gate 	} else {
1940Sstevel@tonic-gate 		tbl->start = (tmp->left_entry ?tmp->left_entry->right_entry:
1950Sstevel@tonic-gate 		    NULL);
1960Sstevel@tonic-gate 	}
1970Sstevel@tonic-gate 	return (tmp->data);
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate size_t
operate_hash(hash * tbl,void (* ptr)(),const char * usr_arg)2010Sstevel@tonic-gate operate_hash(hash *tbl, void (*ptr)(), const char *usr_arg)
2020Sstevel@tonic-gate {
203*12927SRod.Evans@Sun.COM 	hash_entry	*tmp = tbl->start;
204*12927SRod.Evans@Sun.COM 	size_t		c = 0;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	while (tmp) {
2070Sstevel@tonic-gate 		(*ptr)(tmp->data, usr_arg, tmp->key);
2080Sstevel@tonic-gate 		tmp = tmp->left_entry;
2090Sstevel@tonic-gate 		c++;
2100Sstevel@tonic-gate 	}
2110Sstevel@tonic-gate 	return (c);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate size_t
operate_hash_addr(hash * tbl,void (* ptr)(),const char * usr_arg)2150Sstevel@tonic-gate operate_hash_addr(hash *tbl, void (*ptr)(), const char *usr_arg)
2160Sstevel@tonic-gate {
217*12927SRod.Evans@Sun.COM 	hash_entry	*tmp = tbl->start;
218*12927SRod.Evans@Sun.COM 	size_t		c = 0;
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	while (tmp) {
2210Sstevel@tonic-gate 		(*ptr)(&(tmp->data), usr_arg, tmp->key);
2220Sstevel@tonic-gate 		tmp = tmp->left_entry;
2230Sstevel@tonic-gate 		c++;
2240Sstevel@tonic-gate 	}
2250Sstevel@tonic-gate 	return (c);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate void
destroy_hash(hash * tbl,int (* ptr)(),const char * usr_arg)2290Sstevel@tonic-gate destroy_hash(hash *tbl, int (*ptr)(), const char *usr_arg)
2300Sstevel@tonic-gate {
2310Sstevel@tonic-gate 	hash_entry * tmp = tbl->start, * prev;
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	while (tmp) {
2340Sstevel@tonic-gate 		if (ptr) {
2350Sstevel@tonic-gate 			(void) (*ptr)(tmp->data, usr_arg, tmp->key);
2360Sstevel@tonic-gate 		}
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 		if (tbl->hash_type == String_Key) {
2390Sstevel@tonic-gate 			free(tmp->key);
2400Sstevel@tonic-gate 		}
2410Sstevel@tonic-gate 		prev = tmp;
2420Sstevel@tonic-gate 		tmp = tmp->left_entry;
2430Sstevel@tonic-gate 		free((char *)prev);
2440Sstevel@tonic-gate 	}
2450Sstevel@tonic-gate 	free((char *)tbl->table);
2460Sstevel@tonic-gate 	free(tbl);
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate static int
hash_string(const char * s,long modulo)2500Sstevel@tonic-gate hash_string(const char *s, long modulo)
2510Sstevel@tonic-gate {
252*12927SRod.Evans@Sun.COM 	unsigned int	result = 0;
253*12927SRod.Evans@Sun.COM 	int		i = 1;
2540Sstevel@tonic-gate 
255*12927SRod.Evans@Sun.COM 	while (*s != NULL) {
2560Sstevel@tonic-gate 		result += (*s++ << i++);
2570Sstevel@tonic-gate 	}
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	/* LINTED */
2600Sstevel@tonic-gate 	return ((int)(result % modulo));
2610Sstevel@tonic-gate }
262