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