hashp->BSHIFT = __log2(hashp->BSIZE);
hashp->BSHIFT = __log2((uint32)hashp->BSIZE);
static HTAB *init_hash __P((HTAB *, const char *, HASHINFO *));static int   init_htab __P((HTAB *, int));#if BYTE_ORDER == LITTLE_ENDIANstatic void  swap_header __P((HTAB *));static void  swap_header_copy __P((HASHHDR *, HASHHDR *));#endif/* Fast arithmetic, relying on powers of 2, */#define MOD(x, y)		((x) & ((y) - 1))#define RETURN_ERROR(ERR, LOC)	{ save_errno = ERR; goto LOC; }/* Return values */#define	SUCCESS	 (0)#define	DBM_ERROR	(-1)#define	ABNORMAL (1)#ifdef HASH_STATISTICSint hash_accesses, hash_collisions, hash_expansions, hash_overflows;#endif/* A new Lou (montulli@mozilla.com) routine. * * The database is screwed.  Delete it by  * making it a zero length file * * This zero's hashp so that the * database can't be accessed any more */static void__remove_database(DB *dbp){	HTAB *hashp = (HTAB *)dbp->internal;	if (!hashp)		return;	if(hashp->fp != NO_FILE)		close(hashp->fp);	if(hashp->filename)		unlink(hashp->filename);	dbp->internal = NULL; /* zero the internal stuff */}/************************** INTERFACE ROUTINES ***************************//* OPEN/CLOSE */extern DB *__hash_open(const char *file, int flags, int mode, const HASHINFO *info, int dflags){	HTAB *hashp=NULL;	struct stat statbuf;	DB *dbp;	int bpages, hdrsize, new_table, nsegs, save_errno;	if ((flags & O_ACCMODE) == O_WRONLY) {		errno = EINVAL;		RETURN_ERROR(ENOMEM, error0);	}	/* zero the statbuffer so that	 * we can check it for a non-zero	 * date to see if stat succeeded	 */	memset(&statbuf, 0, sizeof(struct stat));	if (!(hashp = (HTAB *)calloc(1, sizeof(HTAB))))		RETURN_ERROR(ENOMEM, error0);	hashp->fp = NO_FILE;	if(file)		hashp->filename = strdup(file);	/*	 * Even if user wants write only, we need to be able to read	 * the actual file, so we need to open it read/write. But, the	 * field in the hashp structure needs to be accurate so that	 * we can check accesses.	 */	hashp->flags = flags;	new_table = 0;	if (!file || (flags & O_TRUNC) 	|| (stat(file, &statbuf)  && (errno == ENOENT))) 	{		if (errno == ENOENT)			errno = 0; /* Just in case someone looks at errno */		new_table = 1;	}	else if(statbuf.st_mtime && statbuf.st_size == 0)	{		/* check for a zero length file and delete it	 	 * if it exists	 	 */		new_table = 1;	}	if (file) {				 #if defined(_WIN32) || defined(_WINDOWS) || defined (macintosh)		if ((hashp->fp = DBFILE_OPEN(file, flags | O_BINARY, mode)) == -1)			RETURN_ERROR(errno, error0);#else 	if ((hashp->fp = open(file, flags, mode)) == -1)		RETURN_ERROR(errno, error0);	(void)fcntl(hashp->fp, F_SETFD, 1);/* We can't use fcntl because of NFS bugs. SIGH */#if 0    {	struct flock fl;	memset(&fl, 0, sizeof(fl));	fl.l_type = F_WRLCK;	if (fcntl(hashp->fp, F_SETLK, &fl) < 0) {#ifdef DEBUG	    fprintf(stderr, "unable to open %s because it's locked (flags=0x%x)\n", file, flags);#endif	    RETURN_ERROR(EACCES, error1);	}    }#endif#endif	}	if (new_table) {		if (!init_hash(hashp, file, (HASHINFO *)info))			RETURN_ERROR(errno, error1);	} else {		/* Table already exists */		if (info && info->hash)			hashp->hash = info->hash;		else			hashp->hash = __default_hash;		hdrsize = read(hashp->fp, (char *)&hashp->hdr, sizeof(HASHHDR));#if BYTE_ORDER == LITTLE_ENDIAN		swap_header(hashp);#endif		if (hdrsize == -1)			RETURN_ERROR(errno, error1);		if (hdrsize != sizeof(HASHHDR))			RETURN_ERROR(EFTYPE, error1);		/* Verify file type, versions and hash function */		if (hashp->MAGIC != HASHMAGIC)			RETURN_ERROR(EFTYPE, error1);#define	OLDHASHVERSION	1		if (hashp->VERSION != HASHVERSION &&		    hashp->VERSION != OLDHASHVERSION)			RETURN_ERROR(EFTYPE, error1);		if (hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY)			RETURN_ERROR(EFTYPE, error1);		if (hashp->NKEYS < 0) {		    /*		    ** OOPS. Old bad database from previously busted		    ** code. Blow it away.		    */		    close(hashp->fp);		    if (remove(file) < 0) {#if defined(DEBUG) && defined(XP_UNIX)			fprintf(stderr,				"WARNING: You have an old bad cache.db file"				" '%s', and I couldn't remove it!\n", file);#endif		    } else {#if defined(DEBUG) && defined(XP_UNIX)			fprintf(stderr,				"WARNING: I blew away your %s file because"				" it was bad due to a recently fixed bug\n",				file);#endif		    }		    RETURN_ERROR(ENOENT, error0);		}		/*		 * Figure out how many segments we need.  Max_Bucket is the		 * maximum bucket number, so the number of buckets is		 * max_bucket + 1.		 */		nsegs = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) /			 hashp->SGSIZE;		hashp->nsegs = 0;		if (alloc_segs(hashp, nsegs))			/*			 * If alloc_segs fails, table will have been destroyed			 * and errno will have been set.			 */			RETURN_ERROR(ENOMEM, error0);		/* Read in bitmaps */		bpages = (hashp->SPARES[hashp->OVFL_POINT] +		    (hashp->BSIZE << BYTE_SHIFT) - 1) >>		    (hashp->BSHIFT + BYTE_SHIFT);		hashp->nmaps = bpages;		(void)memset(&hashp->mapp[0], 0, bpages * sizeof(uint32 *));	}	/* Initialize Buffer Manager */	if (info && info->cachesize)		__buf_init(hashp, (int32) info->cachesize);	else		__buf_init(hashp, DEF_BUFSIZE);	hashp->new_file = new_table;#ifdef macintosh	hashp->save_file = file && !(hashp->flags & O_RDONLY);#else	hashp->save_file = file && (hashp->flags & O_RDWR);#endif	hashp->cbucket = -1;	if (!(dbp = (DB *)malloc(sizeof(DB)))) {		save_errno = errno;		hdestroy(hashp);		errno = save_errno;		RETURN_ERROR(ENOMEM, error0);	}	dbp->internal = hashp;	dbp->close = hash_close;	dbp->del = hash_delete;	dbp->fd = hash_fd;	dbp->get = hash_get;	dbp->put = hash_put;	dbp->seq = hash_seq;	dbp->sync = hash_sync;	dbp->type = DB_HASH;#if 0#if defined(DEBUG) && !defined(_WINDOWS){extern int MKLib_trace_flag;  if(MKLib_trace_flag)	(void)fprintf(stderr,"%s\n%s%lx\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",	    "init_htab:",	    "TABLE POINTER   ", (unsigned long) hashp,	    "BUCKET SIZE     ", hashp->BSIZE,	    "BUCKET SHIFT    ", hashp->BSHIFT,	    "DIRECTORY SIZE  ", hashp->DSIZE,	    "SEGMENT SIZE    ", hashp->SGSIZE,	    "SEGMENT SHIFT   ", hashp->SSHIFT,	    "FILL FACTOR     ", hashp->FFACTOR,	    "MAX BUCKET      ", hashp->MAX_BUCKET,	    "OVFL POINT	     ", hashp->OVFL_POINT,	    "LAST FREED      ", hashp->LAST_FREED,	    "HIGH MASK       ", hashp->HIGH_MASK,	    "LOW  MASK       ", hashp->LOW_MASK,	    "NSEGS           ", hashp->nsegs,	    "NKEYS           ", hashp->NKEYS);}#endif#endif /* 0 */#ifdef HASH_STATISTICS	hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;#endif	return (dbp);error1:	if (hashp != NULL)		(void)close(hashp->fp);error0:	free(hashp);	errno = save_errno;	return (NULL);}static inthash_close(DB *dbp){	HTAB *hashp;	int retval;	if (!dbp)		return (DBM_ERROR);	hashp = (HTAB *)dbp->internal;	if(!hashp)		return (DBM_ERROR);	retval = hdestroy(hashp);	free(dbp);	return (retval);}static int hash_fd(const DB *dbp){	HTAB *hashp;	if (!dbp)		return (DBM_ERROR);	hashp = (HTAB *)dbp->internal;	if(!hashp)		return (DBM_ERROR);	if (hashp->fp == -1) {		errno = ENOENT;		return (-1);	}	return (hashp->fp);}/************************** LOCAL CREATION ROUTINES **********************/static HTAB *init_hash(HTAB *hashp, const char *file, HASHINFO *info){	struct stat statbuf;	int nelem;	nelem = 1;	hashp->NKEYS = 0;	hashp->LORDER = BYTE_ORDER;	hashp->BSIZE = DEF_BUCKET_SIZE;	hashp->BSHIFT = DEF_BUCKET_SHIFT;	hashp->SGSIZE = DEF_SEGSIZE;	hashp->SSHIFT = DEF_SEGSIZE_SHIFT;	hashp->DSIZE = DEF_DIRSIZE;	hashp->FFACTOR = DEF_FFACTOR;	hashp->hash = __default_hash;	memset(hashp->SPARES, 0, sizeof(hashp->SPARES));	memset(hashp->BITMAPS, 0, sizeof (hashp->BITMAPS));	/* Fix bucket size to be optimal for file system */	if (file != NULL) {		if (stat(file, &statbuf))			return (NULL);#if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh) && !defined(VMS)#ifdef __QNX__		hashp->BSIZE = statbuf.st_size;#else		hashp->BSIZE = statbuf.st_blksize;#endif       	/* new code added by Lou to reduce block       	 * size down below MAX_BSIZE       	 */       	if (hashp->BSIZE > MAX_BSIZE)       		hashp->BSIZE = MAX_BSIZE;#endif		hashp->BSHIFT = __log2(hashp->BSIZE);	}	if (info) {		if (info->bsize) {			/* Round pagesize up to power of 2 */			hashp->BSHIFT = __log2(info->bsize);			hashp->BSIZE = 1 << hashp->BSHIFT;			if (hashp->BSIZE > MAX_BSIZE) {				errno = EINVAL;				return (NULL);			}		}		if (info->ffactor)			hashp->FFACTOR = info->ffactor;		if (info->hash)			hashp->hash = info->hash;		if (info->nelem)			nelem = info->nelem;		if (info->lorder) {			if (info->lorder != BIG_ENDIAN &&			    info->lorder != LITTLE_ENDIAN) {				errno = EINVAL;				return (NULL);			}			hashp->LORDER = info->lorder;		}	}	/* init_htab should destroy the table and set errno if it fails */	if (init_htab(hashp, nelem))		return (NULL);	else		return (hashp);}