/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include "pkglib.h"
#include "nhash.h"
#include "pkglocale.h"
#ifndef _KERNEL
#define bcopy(a, b, c) (void) memmove(b, a, c)
#define bcmp memcmp
#define bzero(a, c) (void) memset(a, '\0', c)
#else /* _KERNEL */
#define malloc bkmem_alloc
#endif /* _KERNEL */
#define VERIFY_HASH_REALLOC
static int
BCMP(void *str1, void *str2, int len)
{
return (bcmp((char *)str1, (char *)str2, len));
}
static int
HASH(void *datap, int datalen, int hsz)
{
char *cp;
char *np;
int hv = 0;
/* determine starting and ending positions */
cp = (char *)datap;
np = ((char *)cp + datalen);
/* compute hash over all characters from start to end */
while (cp != np) {
hv += ((int)*cp++);
}
/* return computed hash */
return (hv % hsz);
}
int
init_cache(Cache **cp, int hsz, int bsz,
int (*hfunc)(void *, int, int), int (*cfunc)(void *, void *, int))
{
if ((*cp = (Cache *) malloc(sizeof (**cp))) == NULL) {
(void) fprintf(stderr, pkg_gt("malloc(Cache **cp)"));
return (-1);
}
if (((*cp)->bp =
(Bucket *) malloc(sizeof (*(*cp)->bp) * hsz)) == NULL) {
(void) fprintf(stderr, pkg_gt("malloc(Bucket cp->bp)"));
return (-1);
}
(*cp)->hsz = hsz;
(*cp)->bsz = bsz;
bzero((*cp)->bp, sizeof (*(*cp)->bp) * hsz);
if (hfunc != (int (*)()) NULL) {
(*cp)->hfunc = hfunc;
} else {
(*cp)->hfunc = HASH;
}
if (cfunc != (int (*)()) NULL) {
(*cp)->cfunc = cfunc;
} else {
(*cp)->cfunc = BCMP;
}
return (0);
}
int
add_cache(Cache *cp, Item *itemp)
{
Bucket *bp;
Item **titempp;
/*
* If cp is NULL, then init_cache() wasn't called. Quietly return the
* error code and let the caller deal with it.
*/
if (cp == NULL)
return (-1);
bp = &cp->bp[(*cp->hfunc)(itemp->key, itemp->keyl, cp->hsz)];
if (bp->nent >= bp->nalloc) {
if (bp->nalloc == 0) {
bp->itempp =
(Item **) malloc(sizeof (*bp->itempp) * cp->bsz);
} else {
#ifdef VERIFY_HASH_REALLOC
(void) fprintf(stderr,
pkg_gt("realloc(%d) bucket=%d\n"),
bp->nalloc + cp->bsz,
(*cp->hfunc)(itemp->key, itemp->keyl, cp->hsz));
#endif /* VERIFY_HASH_REALLOC */
if ((titempp =
(Item **) malloc(sizeof (*bp->itempp) *
(bp->nalloc + cp->bsz))) != NULL) {
bcopy((char *)bp->itempp, (char *)titempp,
(sizeof (*bp->itempp) * bp->nalloc));
#ifdef _KERNEL
bkmem_free(bp->itempp,
(sizeof (*bp->itempp) * bp->nalloc));
#else /* !_KERNEL */
free(bp->itempp);
#endif /* _KERNEL */
bp->itempp = titempp;
} else
bp->itempp = NULL;
}
if (bp->itempp == NULL) {
(void) fprintf(stderr,
pkg_gt("add_cache(): out of memory\n"));
return (-1);
}
bp->nalloc += cp->bsz;
}
bp->itempp[bp->nent] = itemp;
bp->nent++;
return (0);
}
Item *
lookup_cache(Cache *cp, void *datap, int datalen)
{
int i;
Bucket *bp;
/*
* If cp is NULL, then init_cache() wasn't called. Quietly return the
* error code and let the caller deal with it.
*/
if (cp == NULL) {
return (Null_Item);
}
bp = &cp->bp[(*cp->hfunc)(datap, datalen, cp->hsz)];
for (i = 0; i < bp->nent; i++) {
if (!(*cp->cfunc)((void *)bp->itempp[i]->key, datap, datalen)) {
return (bp->itempp[i]);
}
}
return (Null_Item);
}