-/* $Header: hash.c,v 3.0.1.2 89/12/21 20:03:39 lwall Locked $
+/* $RCSfile: hash.c,v $$Revision: 4.0.1.1 $$Date: 91/06/07 11:10:11 $
*
- * Copyright (c) 1989, Larry Wall
+ * Copyright (c) 1991, Larry Wall
*
- * You may distribute under the terms of the GNU General Public License
- * as specified in the README file that comes with the perl 3.0 kit.
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
*
* $Log: hash.c,v $
- * Revision 3.0.1.2 89/12/21 20:03:39 lwall
- * patch7: errno may now be a macro with an lvalue
+ * Revision 4.0.1.1 91/06/07 11:10:11 lwall
+ * patch4: new copyright notice
*
- * Revision 3.0.1.1 89/11/11 04:34:18 lwall
- * patch2: CX/UX needed to set the key each time in associative iterators
- *
- * Revision 3.0 89/10/18 15:18:32 lwall
- * 3.0 baseline
+ * Revision 4.0 91/03/20 01:22:26 lwall
+ * 4.0 baseline.
*
*/
#include "EXTERN.h"
#include "perl.h"
+static char coeff[] = {
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
+ 61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1};
+
+static void hfreeentries();
+
STR *
hfetch(tb,key,klen,lval)
register HASH *tb;
char *key;
-int klen;
+unsigned int klen;
int lval;
{
register char *s;
#endif
if (!tb)
- return Nullstr;
+ return &str_undef;
+ if (!tb->tbl_array) {
+ if (lval)
+ Newz(503,tb->tbl_array, tb->tbl_max + 1, HENT*);
+ else
+ return &str_undef;
+ }
/* The hash function we use on symbols has to be equal to the first
* character when taken modulo 128, so that str_reset() can be implemented
if (tb->tbl_dbm) {
dkey.dptr = key;
dkey.dsize = klen;
+#ifdef HAS_GDBM
+ dcontent = gdbm_fetch(tb->tbl_dbm,dkey);
+#else
dcontent = dbm_fetch(tb->tbl_dbm,dkey);
+#endif
if (dcontent.dptr) { /* found one */
str = Str_new(60,dcontent.dsize);
str_nset(str,dcontent.dptr,dcontent.dsize);
hstore(tb,key,klen,str,hash);
return str;
}
- return Nullstr;
+ return &str_undef;
}
bool
hstore(tb,key,klen,val,hash)
register HASH *tb;
char *key;
-int klen;
+unsigned int klen;
STR *val;
register int hash;
{
}
}
+ if (!tb->tbl_array)
+ Newz(505,tb->tbl_array, tb->tbl_max + 1, HENT*);
+
oentry = &(tb->tbl_array[hash & tb->tbl_max]);
i = 1;
}
#ifdef SOME_DBM
else if (tb->tbl_dbm) { /* is this just a cache for dbm file? */
+ void hentdelayfree();
+
entry = tb->tbl_array[hash & tb->tbl_max];
oentry = &entry->hent_next;
entry = *oentry;
while (entry) { /* trim chain down to 1 entry */
*oentry = entry->hent_next;
- hentfree(entry); /* no doubt they'll want this next. */
+ hentdelayfree(entry); /* no doubt they'll want this next. */
entry = *oentry;
}
}
hdelete(tb,key,klen)
register HASH *tb;
char *key;
-int klen;
+unsigned int klen;
{
register char *s;
register int i;
datum dkey;
#endif
- if (!tb)
+ if (!tb || !tb->tbl_array)
return Nullstr;
if (!tb->tbl_coeffsize)
hash = *key + 128 * key[1] + 128 * key[klen-1];
if (bcmp(entry->hent_key,key,klen)) /* is this it? */
continue;
*oentry = entry->hent_next;
- str = str_static(entry->hent_val);
+ str = str_mortal(entry->hent_val);
hentfree(entry);
if (i)
tb->tbl_fill--;
if (tb->tbl_dbm) {
dkey.dptr = key;
dkey.dsize = klen;
+#ifdef HAS_GDBM
+ gdbm_delete(tb->tbl_dbm,dkey);
+#else
dbm_delete(tb->tbl_dbm,dkey);
+#endif
}
#endif
return str;
tb->tbl_max = 127; /* it's a symbol table */
tb->tbl_dosplit = 128; /* so never split */
}
- Newz(503,tb->tbl_array, tb->tbl_max + 1, HENT*);
tb->tbl_fill = 0;
#ifdef SOME_DBM
tb->tbl_dbm = 0;
}
void
-hclear(tb)
-register HASH *tb;
+hentdelayfree(hent)
+register HENT *hent;
{
- register HENT *hent;
- register HENT *ohent = Null(HENT*);
+ if (!hent)
+ return;
+ str_2mortal(hent->hent_val); /* free between statements */
+ Safefree(hent->hent_key);
+ Safefree(hent);
+}
+void
+hclear(tb,dodbm)
+register HASH *tb;
+int dodbm;
+{
if (!tb)
return;
- (void)hiterinit(tb);
- while (hent = hiternext(tb)) { /* concise but not very efficient */
- hentfree(ohent);
- ohent = hent;
- }
- hentfree(ohent);
+ hfreeentries(tb,dodbm);
tb->tbl_fill = 0;
#ifndef lint
- (void)bzero((char*)tb->tbl_array, (tb->tbl_max + 1) * sizeof(HENT*));
+ if (tb->tbl_array)
+ (void)bzero((char*)tb->tbl_array, (tb->tbl_max + 1) * sizeof(HENT*));
#endif
}
-void
-hfree(tb)
+static void
+hfreeentries(tb,dodbm)
register HASH *tb;
+int dodbm;
{
register HENT *hent;
register HENT *ohent = Null(HENT*);
+#ifdef SOME_DBM
+ datum dkey;
+ datum nextdkey;
+#ifdef HAS_GDBM
+ GDBM_FILE old_dbm;
+#else
+#ifdef HAS_NDBM
+ DBM *old_dbm;
+#else
+ int old_dbm;
+#endif
+#endif
+#endif
- if (!tb)
+ if (!tb || !tb->tbl_array)
return;
+#ifdef SOME_DBM
+ if ((old_dbm = tb->tbl_dbm) && dodbm) {
+#ifdef HAS_GDBM
+ while (dkey = gdbm_firstkey(tb->tbl_dbm), dkey.dptr) {
+#else
+ while (dkey = dbm_firstkey(tb->tbl_dbm), dkey.dptr) {
+#endif
+ do {
+#ifdef HAS_GDBM
+ nextdkey = gdbm_nextkey(tb->tbl_dbm, dkey);
+#else
+#ifdef HAS_NDBM
+#ifdef _CX_UX
+ nextdkey = dbm_nextkey(tb->tbl_dbm, dkey);
+#else
+ nextdkey = dbm_nextkey(tb->tbl_dbm);
+#endif
+#else
+ nextdkey = nextkey(dkey);
+#endif
+#endif
+#ifdef HAS_GDBM
+ gdbm_delete(tb->tbl_dbm,dkey);
+#else
+ dbm_delete(tb->tbl_dbm,dkey);
+#endif
+ dkey = nextdkey;
+ } while (dkey.dptr); /* one way or another, this works */
+ }
+ }
+ tb->tbl_dbm = 0; /* now clear just cache */
+#endif
(void)hiterinit(tb);
- while (hent = hiternext(tb)) {
+ while (hent = hiternext(tb)) { /* concise but not very efficient */
hentfree(ohent);
ohent = hent;
}
hentfree(ohent);
+#ifdef SOME_DBM
+ tb->tbl_dbm = old_dbm;
+#endif
+}
+
+void
+hfree(tb,dodbm)
+register HASH *tb;
+int dodbm;
+{
+ if (!tb)
+ return;
+ hfreeentries(tb,dodbm);
Safefree(tb->tbl_array);
Safefree(tb);
}
#ifdef SOME_DBM
if (tb->tbl_dbm) {
if (entry) {
-#ifdef NDBM
+#ifdef HAS_GDBM
+ key.dptr = entry->hent_key;
+ key.dsize = entry->hent_klen;
+ key = gdbm_nextkey(tb->tbl_dbm, key);
+#else
+#ifdef HAS_NDBM
#ifdef _CX_UX
key.dptr = entry->hent_key;
key.dsize = entry->hent_klen;
key.dsize = entry->hent_klen;
key = nextkey(key);
#endif
+#endif
}
else {
Newz(504,entry, 1, HENT);
tb->tbl_eiter = entry;
+#ifdef HAS_GDBM
+ key = gdbm_firstkey(tb->tbl_dbm);
+#else
key = dbm_firstkey(tb->tbl_dbm);
+#endif
}
entry->hent_key = key.dptr;
entry->hent_klen = key.dsize;
return entry;
}
#endif
+ if (!tb->tbl_array)
+ Newz(506,tb->tbl_array, tb->tbl_max + 1, HENT*);
do {
if (entry)
entry = entry->hent_next;
if (tb->tbl_dbm) {
key.dptr = entry->hent_key;
key.dsize = entry->hent_klen;
+#ifdef HAS_GDBM
+ content = gdbm_fetch(tb->tbl_dbm,key);
+#else
content = dbm_fetch(tb->tbl_dbm,key);
+#endif
if (!entry->hent_val)
entry->hent_val = Str_new(62,0);
str_nset(entry->hent_val,content.dptr,content.dsize);
}
#ifdef SOME_DBM
-#if defined(FCNTL) && ! defined(O_CREAT)
-#include <fcntl.h>
+
+#ifndef O_CREAT
+# ifdef I_FCNTL
+# include <fcntl.h>
+# endif
+# ifdef I_SYS_FILE
+# include <sys/file.h>
+# endif
#endif
#ifndef O_RDONLY
#define O_CREAT 01000
#endif
-#ifndef NDBM
+#ifdef HAS_ODBM
static int dbmrefcnt = 0;
#endif
{
if (!tb)
return FALSE;
-#ifndef NDBM
+#ifdef HAS_ODBM
if (tb->tbl_dbm) /* never really closed it */
return TRUE;
#endif
- if (tb->tbl_dbm)
+ if (tb->tbl_dbm) {
hdbmclose(tb);
- hclear(tb);
-#ifdef NDBM
- tb->tbl_dbm = dbm_open(fname, O_RDWR|O_CREAT, mode);
- if (!tb->tbl_dbm) /* oops, just try reading it */
+ tb->tbl_dbm = 0;
+ }
+ hclear(tb, FALSE); /* clear cache */
+#ifdef HAS_GDBM
+ if (mode >= 0)
+ tb->tbl_dbm = gdbm_open(fname, 0, GDBM_WRCREAT,mode, (void *) NULL);
+ if (!tb->tbl_dbm)
+ tb->tbl_dbm = gdbm_open(fname, 0, GDBM_WRITER, mode, (void *) NULL);
+ if (!tb->tbl_dbm)
+ tb->tbl_dbm = gdbm_open(fname, 0, GDBM_READER, mode, (void *) NULL);
+#else
+#ifdef HAS_NDBM
+ if (mode >= 0)
+ tb->tbl_dbm = dbm_open(fname, O_RDWR|O_CREAT, mode);
+ if (!tb->tbl_dbm)
+ tb->tbl_dbm = dbm_open(fname, O_RDWR, mode);
+ if (!tb->tbl_dbm)
tb->tbl_dbm = dbm_open(fname, O_RDONLY, mode);
#else
if (dbmrefcnt++)
fatal("Old dbm can only open one database");
sprintf(buf,"%s.dir",fname);
if (stat(buf, &statbuf) < 0) {
- if (close(creat(buf,mode)) < 0)
+ if (mode < 0 || close(creat(buf,mode)) < 0)
return FALSE;
sprintf(buf,"%s.pag",fname);
if (close(creat(buf,mode)) < 0)
}
tb->tbl_dbm = dbminit(fname) >= 0;
#endif
+#endif
+ if (!tb->tbl_array && tb->tbl_dbm != 0)
+ Newz(507,tb->tbl_array, tb->tbl_max + 1, HENT*);
return tb->tbl_dbm != 0;
}
register HASH *tb;
{
if (tb && tb->tbl_dbm) {
-#ifdef NDBM
+#ifdef HAS_GDBM
+ gdbm_close(tb->tbl_dbm);
+ tb->tbl_dbm = 0;
+#else
+#ifdef HAS_NDBM
dbm_close(tb->tbl_dbm);
tb->tbl_dbm = 0;
#else
/* dbmrefcnt--; */ /* doesn't work, rats */
#endif
+#endif
}
else if (dowarn)
warn("Close on unopened dbm file");
hdbmstore(tb,key,klen,str)
register HASH *tb;
char *key;
-int klen;
+unsigned int klen;
register STR *str;
{
datum dkey, dcontent;
dkey.dsize = klen;
dcontent.dptr = str_get(str);
dcontent.dsize = str->str_cur;
+#ifdef HAS_GDBM
+ error = gdbm_store(tb->tbl_dbm, dkey, dcontent, GDBM_REPLACE);
+#else
error = dbm_store(tb->tbl_dbm, dkey, dcontent, DBM_REPLACE);
+#endif
if (error) {
if (errno == EPERM)
fatal("No write permission to dbm file");
warn("dbm store returned %d, errno %d, key \"%s\"",error,errno,key);
-#ifdef NDBM
+#ifdef HAS_NDBM
dbm_clearerr(tb->tbl_dbm);
#endif
}