Use PERL=../miniperl
[p5sagit/p5-mst-13.2.git] / hv.c
diff --git a/hv.c b/hv.c
index e62432d..852ee16 100644 (file)
--- a/hv.c
+++ b/hv.c
@@ -1,35 +1,59 @@
-/* $RCSfile: hash.c,v $$Revision: 4.1 $$Date: 92/08/07 18:21:48 $
+/*    hv.c
  *
- *    Copyright (c) 1991, Larry Wall
+ *    Copyright (c) 1991-1994, Larry Wall
  *
  *    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 4.1  92/08/07  18:21:48  lwall
- * 
- * Revision 4.0.1.3  92/06/08  13:26:29  lwall
- * patch20: removed implicit int declarations on functions
- * patch20: delete could cause %array to give too low a count of buckets filled
- * patch20: hash tables now split only if the memory is available to do so
- * 
- * Revision 4.0.1.2  91/11/05  17:24:13  lwall
- * patch11: saberized perl
- * 
- * Revision 4.0.1.1  91/06/07  11:10:11  lwall
- * patch4: new copyright notice
- * 
- * Revision 4.0  91/03/20  01:22:26  lwall
- * 4.0 baseline.
- * 
+ */
+
+/*
+ * "I sit beside the fire and think of all that I have seen."  --Bilbo
  */
 
 #include "EXTERN.h"
 #include "perl.h"
 
-static void hsplit();
+static void hsplit _((HV *hv));
+static void hfreeentries _((HV *hv));
+
+static HE* more_he();
+
+static HE*
+new_he()
+{
+    HE* he;
+    if (he_root) {
+        he = he_root;
+        he_root = (HE*)he->hent_next;
+        return he;
+    }
+    return more_he();
+}
 
-static void hfreeentries();
+static void
+del_he(p)
+HE* p;
+{
+    p->hent_next = (HE*)he_root;
+    he_root = p;
+}
+
+static HE*
+more_he()
+{
+    register HE* he;
+    register HE* heend;
+    he_root = (HE*)safemalloc(1008);
+    he = he_root;
+    heend = &he[1008 / sizeof(HE) - 1];
+    while (he < heend) {
+        he->hent_next = (HE*)(he + 1);
+        he++;
+    }
+    he->hent_next = 0;
+    return new_he();
+}
 
 SV**
 hv_fetch(hv,key,klen,lval)
@@ -43,44 +67,39 @@ I32 lval;
     register I32 i;
     register I32 hash;
     register HE *entry;
-    register I32 maxi;
     SV *sv;
-#ifdef SOME_DBM
-    datum dkey,dcontent;
-#endif
 
     if (!hv)
        return 0;
+
+    if (SvRMAGICAL(hv)) {
+       if (mg_find((SV*)hv,'P')) {
+           sv = sv_newmortal();
+           mg_copy((SV*)hv, sv, key, klen);
+           Sv = sv;
+           return &Sv;
+       }
+    }
+
     xhv = (XPVHV*)SvANY(hv);
     if (!xhv->xhv_array) {
-       if (lval)
-           Newz(503,xhv->xhv_array, xhv->xhv_max + 1, HE*);
+       if (lval 
+#ifdef DYNAMIC_ENV_FETCH  /* if it's an %ENV lookup, we may get it on the fly */
+                || (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME))
+#endif
+                                                                 )
+           Newz(503,xhv->xhv_array, sizeof(HE*) * (xhv->xhv_max + 1), char);
        else
            return 0;
     }
 
-    /* The hash function we use on symbols has to be equal to the first
-     * character when taken modulo 128, so that sv_reset() can be implemented
-     * efficiently.  We throw in the second character and the last character
-     * (times 128) so that long chains of identifiers starting with the
-     * same letter don't have to be strEQ'ed within hv_fetch(), since it
-     * compares hash values before trying strEQ().
-     */
-    if (!xhv->xhv_coeffsize && klen)
-       hash = klen ? *key + 128 * key[1] + 128 * key[klen-1] : 0;
-    else {     /* use normal coefficients */
-       if (klen < xhv->xhv_coeffsize)
-           maxi = klen;
-       else
-           maxi = xhv->xhv_coeffsize;
-       for (s=key,             i=0,    hash = 0;
-                           i < maxi;                   /*SUPPRESS 8*/
-            s++,               i++,    hash *= 5) {
-           hash += *s * coeff[i];
-       }
-    }
+    i = klen;
+    hash = 0;
+    s = key;
+    while (i--)
+       hash = hash * 33 + *s++;
 
-    entry = xhv->xhv_array[hash & xhv->xhv_max];
+    entry = ((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max];
     for (; entry; entry = entry->hent_next) {
        if (entry->hent_hash != hash)           /* strings can't be equal */
            continue;
@@ -90,20 +109,15 @@ I32 lval;
            continue;
        return &entry->hent_val;
     }
-#ifdef SOME_DBM
-    if (xhv->xhv_dbm) {
-       dkey.dptr = key;
-       dkey.dsize = klen;
-#ifdef HAS_GDBM
-       dcontent = gdbm_fetch(xhv->xhv_dbm,dkey);
-#else
-       dcontent = dbm_fetch(xhv->xhv_dbm,dkey);
-#endif
-       if (dcontent.dptr) {                    /* found one */
-           sv = NEWSV(60,dcontent.dsize);
-           sv_setpvn(sv,dcontent.dptr,dcontent.dsize);
-           return hv_store(hv,key,klen,sv,hash);               /* cache it */
-       }
+#ifdef DYNAMIC_ENV_FETCH  /* %ENV lookup?  If so, try to fetch the value now */
+    if (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME)) {
+      char *gotenv;
+
+      gotenv = my_getenv(key);
+      if (gotenv != NULL) {
+        sv = newSVpv(gotenv,strlen(gotenv));
+        return hv_store(hv,key,klen,sv,hash);
+      }
     }
 #endif
     if (lval) {                /* gonna assign to this, so it better be there */
@@ -119,46 +133,42 @@ HV *hv;
 char *key;
 U32 klen;
 SV *val;
-register I32 hash;
+register U32 hash;
 {
     register XPVHV* xhv;
     register char *s;
     register I32 i;
     register HE *entry;
     register HE **oentry;
-    register I32 maxi;
 
     if (!hv)
        return 0;
 
     xhv = (XPVHV*)SvANY(hv);
-    if (hash)
-       /*SUPPRESS 530*/
-       ;
-    else if (!xhv->xhv_coeffsize && klen)
-       hash = klen ? *key + 128 * key[1] + 128 * key[klen-1] : 0;
-    else {     /* use normal coefficients */
-       if (klen < xhv->xhv_coeffsize)
-           maxi = klen;
-       else
-           maxi = xhv->xhv_coeffsize;
-       for (s=key,             i=0,    hash = 0;
-                           i < maxi;                   /*SUPPRESS 8*/
-            s++,               i++,    hash *= 5) {
-           hash += *s * coeff[i];
-       }
+    if (SvMAGICAL(hv)) {
+       mg_copy((SV*)hv, val, key, klen);
+#ifndef OVERLOAD
+       if (!xhv->xhv_array)
+           return 0;
+#else
+       if (!xhv->xhv_array && (SvMAGIC(hv)->mg_type != 'A'
+                               || SvMAGIC(hv)->mg_moremagic))
+         return 0;
+#endif /* OVERLOAD */
+    }
+    if (!hash) {
+    i = klen;
+    s = key;
+    while (i--)
+       hash = hash * 33 + *s++;
     }
 
     if (!xhv->xhv_array)
-       Newz(505,xhv->xhv_array, xhv->xhv_max + 1, HE*);
+       Newz(505, xhv->xhv_array, sizeof(HE**) * (xhv->xhv_max + 1), char);
 
-    oentry = &(xhv->xhv_array[hash & xhv->xhv_max]);
+    oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max];
     i = 1;
 
-    if (SvMAGICAL(hv)) {
-       MAGIC* mg = SvMAGIC(hv);
-       sv_magic(val, (SV*)hv, tolower(mg->mg_type), key, klen);
-    }
     for (entry = *oentry; entry; i=0, entry = entry->hent_next) {
        if (entry->hent_hash != hash)           /* strings can't be equal */
            continue;
@@ -166,54 +176,35 @@ register I32 hash;
            continue;
        if (bcmp(entry->hent_key,key,klen))     /* is this it? */
            continue;
-       sv_free(entry->hent_val);
+       SvREFCNT_dec(entry->hent_val);
        entry->hent_val = val;
        return &entry->hent_val;
     }
-    New(501,entry, 1, HE);
 
+    entry = new_he();
     entry->hent_klen = klen;
-    entry->hent_key = nsavestr(key,klen);
+    entry->hent_key = savepvn(key,klen);
     entry->hent_val = val;
     entry->hent_hash = hash;
     entry->hent_next = *oentry;
     *oentry = entry;
 
-    /* hv_dbmstore not necessary here because it's called from sv_setmagic() */
-
+    xhv->xhv_keys++;
     if (i) {                           /* initial entry? */
-       xhv->xhv_fill++;
-#ifdef SOME_DBM
-       if (xhv->xhv_dbm && xhv->xhv_max >= DBM_CACHE_MAX)
-           return &entry->hent_val;
-#endif
-       if (xhv->xhv_fill > xhv->xhv_dosplit)
+       ++xhv->xhv_fill;
+       if (xhv->xhv_keys > xhv->xhv_max)
            hsplit(hv);
     }
-#ifdef SOME_DBM
-    else if (xhv->xhv_dbm) {           /* is this just a cache for dbm file? */
-       void he_delayfree();
-       HE* ent;
-
-       ent = xhv->xhv_array[hash & xhv->xhv_max];
-       oentry = &ent->hent_next;
-       ent = *oentry;
-       while (ent) {   /* trim chain down to 1 entry */
-           *oentry = ent->hent_next;
-           he_delayfree(ent);  /* no doubt they'll want this next, sigh... */
-           ent = *oentry;
-       }
-    }
-#endif
 
     return &entry->hent_val;
 }
 
 SV *
-hv_delete(hv,key,klen)
+hv_delete(hv,key,klen,flags)
 HV *hv;
 char *key;
 U32 klen;
+I32 flags;
 {
     register XPVHV* xhv;
     register char *s;
@@ -222,31 +213,27 @@ U32 klen;
     register HE *entry;
     register HE **oentry;
     SV *sv;
-    I32 maxi;
-#ifdef SOME_DBM
-    datum dkey;
-#endif
 
     if (!hv)
        return Nullsv;
+    if (SvRMAGICAL(hv)) {
+       sv = *hv_fetch(hv, key, klen, TRUE);
+       mg_clear(sv);
+       if (mg_find(sv, 'p')) {
+           sv_unmagic(sv, 'p');        /* No longer an element */
+           return sv;
+       }
+    }
     xhv = (XPVHV*)SvANY(hv);
     if (!xhv->xhv_array)
        return Nullsv;
-    if (!xhv->xhv_coeffsize && klen)
-       hash = klen ? *key + 128 * key[1] + 128 * key[klen-1] : 0;
-    else {     /* use normal coefficients */
-       if (klen < xhv->xhv_coeffsize)
-           maxi = klen;
-       else
-           maxi = xhv->xhv_coeffsize;
-       for (s=key,             i=0,    hash = 0;
-                           i < maxi;                   /*SUPPRESS 8*/
-            s++,               i++,    hash *= 5) {
-           hash += *s * coeff[i];
-       }
-    }
+    i = klen;
+    hash = 0;
+    s = key;
+    while (i--)
+       hash = hash * 33 + *s++;
 
-    oentry = &(xhv->xhv_array[hash & xhv->xhv_max]);
+    oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max];
     entry = *oentry;
     i = 1;
     for (; entry; i=0, oentry = &entry->hent_next, entry = *oentry) {
@@ -259,28 +246,66 @@ U32 klen;
        *oentry = entry->hent_next;
        if (i && !*oentry)
            xhv->xhv_fill--;
-       sv = sv_mortalcopy(entry->hent_val);
-       he_free(entry);
-#ifdef SOME_DBM
-      do_dbm_delete:
-       if (xhv->xhv_dbm) {
-           dkey.dptr = key;
-           dkey.dsize = klen;
-#ifdef HAS_GDBM
-           gdbm_delete(xhv->xhv_dbm,dkey);
-#else
-           dbm_delete(xhv->xhv_dbm,dkey);
-#endif
-       }
-#endif
+       if (flags & G_DISCARD)
+           sv = Nullsv;
+       else
+           sv = sv_mortalcopy(entry->hent_val);
+       if (entry == xhv->xhv_eiter)
+           entry->hent_klen = -1;
+       else
+           he_free(entry);
+       --xhv->xhv_keys;
        return sv;
     }
-#ifdef SOME_DBM
-    sv = Nullsv;
-    goto do_dbm_delete;
-#else
     return Nullsv;
-#endif
+}
+
+bool
+hv_exists(hv,key,klen)
+HV *hv;
+char *key;
+U32 klen;
+{
+    register XPVHV* xhv;
+    register char *s;
+    register I32 i;
+    register I32 hash;
+    register HE *entry;
+    SV *sv;
+
+    if (!hv)
+       return 0;
+
+    if (SvRMAGICAL(hv)) {
+       if (mg_find((SV*)hv,'P')) {
+           sv = sv_newmortal();
+           mg_copy((SV*)hv, sv, key, klen); 
+           magic_existspack(sv, mg_find(sv, 'p'));
+           return SvTRUE(sv);
+       }
+    }
+
+    xhv = (XPVHV*)SvANY(hv);
+    if (!xhv->xhv_array)
+       return 0; 
+
+    i = klen;
+    hash = 0;
+    s = key;
+    while (i--)
+       hash = hash * 33 + *s++;
+
+    entry = ((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max];
+    for (; entry; entry = entry->hent_next) {
+       if (entry->hent_hash != hash)           /* strings can't be equal */
+           continue;
+       if (entry->hent_klen != klen)
+           continue;
+       if (bcmp(entry->hent_key,key,klen))     /* is this it? */
+           continue;
+       return TRUE;
+    }
+    return FALSE;
 }
 
 static void
@@ -288,26 +313,44 @@ hsplit(hv)
 HV *hv;
 {
     register XPVHV* xhv = (XPVHV*)SvANY(hv);
-    I32 oldsize = xhv->xhv_max + 1;
+    I32 oldsize = (I32) xhv->xhv_max + 1; /* sic(k) */
     register I32 newsize = oldsize * 2;
     register I32 i;
     register HE **a;
     register HE **b;
     register HE *entry;
     register HE **oentry;
+    I32 tmp;
 
-    a = xhv->xhv_array;
+    a = (HE**)xhv->xhv_array;
     nomemok = TRUE;
+#ifdef STRANGE_MALLOC
     Renew(a, newsize, HE*);
-    nomemok = FALSE;
-    if (!a) {
-       xhv->xhv_dosplit = xhv->xhv_max + 1;    /* never split again */
-       return;
+#else
+    i = newsize * sizeof(HE*);
+#define MALLOC_OVERHEAD 16
+    tmp = MALLOC_OVERHEAD;
+    while (tmp - MALLOC_OVERHEAD < i)
+       tmp += tmp;
+    tmp -= MALLOC_OVERHEAD;
+    tmp /= sizeof(HE*);
+    assert(tmp >= newsize);
+    New(2,a, tmp, HE*);
+    Copy(xhv->xhv_array, a, oldsize, HE*);
+    if (oldsize >= 64 && *(char*)&xhv->xnv_nv == 0) {
+       sv_add_arena((char*)xhv->xhv_array, oldsize * sizeof(HE*), 0);
+       sv_add_arena(((char*)a) + newsize * sizeof(HE*),
+                    newsize * sizeof(HE*) - MALLOC_OVERHEAD,
+                    SVf_FAKE);
     }
+    else
+       Safefree(xhv->xhv_array);
+#endif
+
+    nomemok = FALSE;
     Zero(&a[oldsize], oldsize, HE*);           /* zero 2nd half*/
     xhv->xhv_max = --newsize;
-    xhv->xhv_dosplit = xhv->xhv_max * FILLPCT / 100;
-    xhv->xhv_array = a;
+    xhv->xhv_array = (char*)a;
 
     for (i=0; i<oldsize; i++,a++) {
        if (!*a)                                /* non-existent */
@@ -331,32 +374,20 @@ HV *hv;
 }
 
 HV *
-newHV(lookat)
-U32 lookat;
+newHV()
 {
     register HV *hv;
     register XPVHV* xhv;
 
-    Newz(502,hv, 1, HV);
-    SvREFCNT(hv) = 1;
-    sv_upgrade(hv, SVt_PVHV);
+    hv = (HV*)NEWSV(502,0);
+    sv_upgrade((SV *)hv, SVt_PVHV);
     xhv = (XPVHV*)SvANY(hv);
     SvPOK_off(hv);
     SvNOK_off(hv);
-    if (lookat) {
-       xhv->xhv_coeffsize = lookat;
-       xhv->xhv_max = 7;               /* it's a normal associative array */
-       xhv->xhv_dosplit = xhv->xhv_max * FILLPCT / 100;
-    }
-    else {
-       xhv->xhv_max = 127;             /* it's a symbol table */
-       xhv->xhv_dosplit = 128;         /* so never split */
-    }
+    xhv->xhv_max = 7;          /* start with 8 buckets */
     xhv->xhv_fill = 0;
     xhv->xhv_pmroot = 0;
-#ifdef SOME_DBM
-    xhv->xhv_dbm = 0;
-#endif
+    *(char*)&xhv->xnv_nv = 0;
     (void)hv_iterinit(hv);     /* so each() will start off right */
     return hv;
 }
@@ -367,9 +398,9 @@ register HE *hent;
 {
     if (!hent)
        return;
-    sv_free(hent->hent_val);
+    SvREFCNT_dec(hent->hent_val);
     Safefree(hent->hent_key);
-    Safefree(hent);
+    del_he(hent);
 }
 
 void
@@ -380,136 +411,90 @@ register HE *hent;
        return;
     sv_2mortal(hent->hent_val);        /* free between statements */
     Safefree(hent->hent_key);
-    Safefree(hent);
+    del_he(hent);
 }
 
 void
-hv_clear(hv,dodbm)
+hv_clear(hv)
 HV *hv;
-I32 dodbm;
 {
     register XPVHV* xhv;
     if (!hv)
        return;
     xhv = (XPVHV*)SvANY(hv);
-    hfreeentries(hv,dodbm);
+    hfreeentries(hv);
     xhv->xhv_fill = 0;
-#ifndef lint
+    xhv->xhv_keys = 0;
     if (xhv->xhv_array)
-       (void)memzero((char*)xhv->xhv_array, (xhv->xhv_max + 1) * sizeof(HE*));
-#endif
+       (void)memzero(xhv->xhv_array, (xhv->xhv_max + 1) * sizeof(HE*));
+
+    if (SvRMAGICAL(hv))
+       mg_clear((SV*)hv); 
 }
 
 static void
-hfreeentries(hv,dodbm)
+hfreeentries(hv)
 HV *hv;
-I32 dodbm;
 {
-    register XPVHV* xhv;
+    register HE **array;
     register HE *hent;
     register HE *ohent = Null(HE*);
-#ifdef SOME_DBM
-    datum dkey;
-    datum nextdkey;
-#ifdef HAS_GDBM
-    GDBM_FILE old_dbm;
-#else
-#ifdef HAS_NDBM
-    DBM *old_dbm;
-#else
-    I32 old_dbm;
-#endif
-#endif
-#endif
+    I32 riter;
+    I32 max;
 
     if (!hv)
        return;
-    xhv = (XPVHV*)SvANY(hv);
-    if (!xhv->xhv_array)
+    if (!HvARRAY(hv))
        return;
-#ifdef SOME_DBM
-    if ((old_dbm = xhv->xhv_dbm) && dodbm) {
-#ifdef HAS_GDBM
-       while (dkey = gdbm_firstkey(xhv->xhv_dbm), dkey.dptr) {
-#else
-       while (dkey = dbm_firstkey(xhv->xhv_dbm), dkey.dptr) {
-#endif
-           do {
-#ifdef HAS_GDBM
-               nextdkey = gdbm_nextkey(xhv->xhv_dbm, dkey);
-#else
-#ifdef HAS_NDBM
-#ifdef _CX_UX
-               nextdkey = dbm_nextkey(xhv->xhv_dbm, dkey);
-#else
-               nextdkey = dbm_nextkey(xhv->xhv_dbm);
-#endif
-#else
-               nextdkey = nextkey(dkey);
-#endif
-#endif
-#ifdef HAS_GDBM
-               gdbm_delete(xhv->xhv_dbm,dkey);
-#else
-               dbm_delete(xhv->xhv_dbm,dkey);
-#endif
-               dkey = nextdkey;
-           } while (dkey.dptr);        /* one way or another, this works */
+
+    riter = 0;
+    max = HvMAX(hv);
+    array = HvARRAY(hv);
+    hent = array[0];
+    for (;;) {
+       if (hent) {
+           ohent = hent;
+           hent = hent->hent_next;
+           he_free(ohent);
        }
+       if (!hent) {
+           if (++riter > max)
+               break;
+           hent = array[riter];
+       } 
     }
-    xhv->xhv_dbm = 0;                  /* now clear just cache */
-#endif
     (void)hv_iterinit(hv);
-    /*SUPPRESS 560*/
-    while (hent = hv_iternext(hv)) {   /* concise but not very efficient */
-       he_free(ohent);
-       ohent = hent;
-    }
-    he_free(ohent);
-#ifdef SOME_DBM
-    xhv->xhv_dbm = old_dbm;
-#endif
-    if (SvMAGIC(hv))
-       mg_clear(hv);
 }
 
 void
-hv_undef(hv,dodbm)
+hv_undef(hv)
 HV *hv;
-I32 dodbm;
 {
     register XPVHV* xhv;
     if (!hv)
        return;
     xhv = (XPVHV*)SvANY(hv);
-    hfreeentries(hv,dodbm);
+    hfreeentries(hv);
+#ifdef STRANGE_MALLOC
     Safefree(xhv->xhv_array);
-    xhv->xhv_array = 0;
-    if (xhv->xhv_coeffsize) {
-       xhv->xhv_max = 7;               /* it's a normal associative array */
-       xhv->xhv_dosplit = xhv->xhv_max * FILLPCT / 100;
-    }
-    else {
-       xhv->xhv_max = 127;             /* it's a symbol table */
-       xhv->xhv_dosplit = 128;         /* so never split */
+#else
+    if (xhv->xhv_max < 127 || *(char*)&xhv->xnv_nv)
+       Safefree(xhv->xhv_array);
+    else  /* We used last half, so use first half for SV arena too. */
+       sv_add_arena((char*)xhv->xhv_array, (xhv->xhv_max + 1) * sizeof(HE*),0);
+#endif
+    if (HvNAME(hv)) {
+       Safefree(HvNAME(hv));
+       HvNAME(hv) = 0;
     }
+    xhv->xhv_array = 0;
+    xhv->xhv_max = 7;          /* it's a normal associative array */
     xhv->xhv_fill = 0;
-#ifdef SOME_DBM
-    xhv->xhv_dbm = 0;
-#endif
-    (void)hv_iterinit(hv);     /* so each() will start off right */
-}
+    xhv->xhv_keys = 0;
+    *(char*)&xhv->xnv_nv = 1;
 
-void
-hv_free(hv,dodbm)
-register HV *hv;
-I32 dodbm;
-{
-    if (!hv)
-       return;
-    hfreeentries(hv,dodbm);
-    Safefree(HvARRAY(hv));
-    Safefree(hv);
+    if (SvRMAGICAL(hv))
+       mg_clear((SV*)hv); 
 }
 
 I32
@@ -517,6 +502,9 @@ hv_iterinit(hv)
 HV *hv;
 {
     register XPVHV* xhv = (XPVHV*)SvANY(hv);
+    HE *entry = xhv->xhv_eiter;
+    if (entry && entry->hent_klen < 0) /* was deleted earlier? */
+       he_free(entry);
     xhv->xhv_riter = -1;
     xhv->xhv_eiter = Null(HE*);
     return xhv->xhv_fill;
@@ -528,73 +516,58 @@ HV *hv;
 {
     register XPVHV* xhv;
     register HE *entry;
-#ifdef SOME_DBM
-    datum key;
-#endif
+    HE *oldentry;
+    MAGIC* mg;
 
     if (!hv)
-       fatal("Bad associative array");
+       croak("Bad associative array");
     xhv = (XPVHV*)SvANY(hv);
-    entry = xhv->xhv_eiter;
-#ifdef SOME_DBM
-    if (xhv->xhv_dbm) {
+    oldentry = entry = xhv->xhv_eiter;
+
+    if (SvRMAGICAL(hv) && (mg = mg_find((SV*)hv,'P'))) {
+       SV *key = sv_newmortal();
        if (entry) {
-#ifdef HAS_GDBM
-           key.dptr = entry->hent_key;
-           key.dsize = entry->hent_klen;
-           key = gdbm_nextkey(xhv->xhv_dbm, key);
-#else
-#ifdef HAS_NDBM
-#ifdef _CX_UX
-           key.dptr = entry->hent_key;
-           key.dsize = entry->hent_klen;
-           key = dbm_nextkey(xhv->xhv_dbm, key);
-#else
-           key = dbm_nextkey(xhv->xhv_dbm);
-#endif /* _CX_UX */
-#else
-           key.dptr = entry->hent_key;
-           key.dsize = entry->hent_klen;
-           key = nextkey(key);
-#endif
-#endif
+           sv_usepvn(key, entry->hent_key, entry->hent_klen);
+           entry->hent_key = 0;
        }
        else {
-           Newz(504,entry, 1, HE);
-           xhv->xhv_eiter = entry;
-#ifdef HAS_GDBM
-           key = gdbm_firstkey(xhv->xhv_dbm);
-#else
-           key = dbm_firstkey(xhv->xhv_dbm);
-#endif
+           xhv->xhv_eiter = entry = new_he();
+           Zero(entry, 1, HE);
        }
-       entry->hent_key = key.dptr;
-       entry->hent_klen = key.dsize;
-       if (!key.dptr) {
-           if (entry->hent_val)
-               sv_free(entry->hent_val);
-           Safefree(entry);
-           xhv->xhv_eiter = Null(HE*);
-           return Null(HE*);
-       }
-       return entry;
+       magic_nextpack((SV*) hv,mg,key);
+        if (SvOK(key)) {
+           STRLEN len;
+           entry->hent_key = SvPV_force(key, len);
+           entry->hent_klen = len;
+           SvPOK_off(key);
+           SvPVX(key) = 0;
+           return entry;
+        }
+       if (entry->hent_val)
+           SvREFCNT_dec(entry->hent_val);
+       del_he(entry);
+       xhv->xhv_eiter = Null(HE*);
+       return Null(HE*);
     }
-#endif
+
     if (!xhv->xhv_array)
-       Newz(506,xhv->xhv_array, xhv->xhv_max + 1, HE*);
+       Newz(506,xhv->xhv_array, sizeof(HE*) * (xhv->xhv_max + 1), char);
     do {
        if (entry)
            entry = entry->hent_next;
        if (!entry) {
-           xhv->xhv_riter++;
+           ++xhv->xhv_riter;
            if (xhv->xhv_riter > xhv->xhv_max) {
                xhv->xhv_riter = -1;
                break;
            }
-           entry = xhv->xhv_array[xhv->xhv_riter];
+           entry = ((HE**)xhv->xhv_array)[xhv->xhv_riter];
        }
     } while (!entry);
 
+    if (oldentry && oldentry->hent_klen < 0)   /* was deleted earlier? */
+       he_free(oldentry);
+
     xhv->xhv_eiter = entry;
     return entry;
 }
@@ -613,195 +586,34 @@ hv_iterval(hv,entry)
 HV *hv;
 register HE *entry;
 {
-#ifdef SOME_DBM
-    register XPVHV* xhv;
-    datum key, content;
-
-    if (!hv)
-       fatal("Bad associative array");
-    xhv = (XPVHV*)SvANY(hv);
-    if (xhv->xhv_dbm) {
-       key.dptr = entry->hent_key;
-       key.dsize = entry->hent_klen;
-#ifdef HAS_GDBM
-       content = gdbm_fetch(xhv->xhv_dbm,key);
-#else
-       content = dbm_fetch(xhv->xhv_dbm,key);
-#endif
-       if (!entry->hent_val)
-           entry->hent_val = NEWSV(62,0);
-       sv_setpvn(entry->hent_val,content.dptr,content.dsize);
+    if (SvRMAGICAL(hv)) {
+       if (mg_find((SV*)hv,'P')) {
+           SV* sv = sv_newmortal();
+           mg_copy((SV*)hv, sv, entry->hent_key, entry->hent_klen);
+           return sv;
+       }
     }
-#endif
     return entry->hent_val;
 }
 
-#ifdef SOME_DBM
-
-#ifndef OP_CREAT
-#  ifdef I_FCNTL
-#    include <fcntl.h>
-#  endif
-#  ifdef I_SYS_FILE
-#    include <sys/file.h>
-#  endif
-#endif
-
-#ifndef OP_RDONLY
-#define OP_RDONLY 0
-#endif
-#ifndef OP_RDWR
-#define OP_RDWR 2
-#endif
-#ifndef OP_CREAT
-#define OP_CREAT 01000
-#endif
-
-bool
-hv_dbmopen(hv,fname,mode)
-HV *hv;
-char *fname;
-I32 mode;
-{
-    register XPVHV* xhv;
-    if (!hv)
-       return FALSE;
-    xhv = (XPVHV*)SvANY(hv);
-#ifdef HAS_ODBM
-    if (xhv->xhv_dbm)  /* never really closed it */
-       return TRUE;
-#endif
-    if (xhv->xhv_dbm) {
-       hv_dbmclose(hv);
-       xhv->xhv_dbm = 0;
-    }
-    hv_clear(hv, FALSE);       /* clear cache */
-#ifdef HAS_GDBM
-    if (mode >= 0)
-       xhv->xhv_dbm = gdbm_open(fname, 0, GDBM_WRCREAT,mode, (void *) NULL);
-    if (!xhv->xhv_dbm)
-       xhv->xhv_dbm = gdbm_open(fname, 0, GDBM_WRITER, mode, (void *) NULL);
-    if (!xhv->xhv_dbm)
-       xhv->xhv_dbm = gdbm_open(fname, 0, GDBM_READER, mode, (void *) NULL);
-#else
-#ifdef HAS_NDBM
-    if (mode >= 0)
-       xhv->xhv_dbm = dbm_open(fname, OP_RDWR|OP_CREAT, mode);
-    if (!xhv->xhv_dbm)
-       xhv->xhv_dbm = dbm_open(fname, OP_RDWR, mode);
-    if (!xhv->xhv_dbm)
-       xhv->xhv_dbm = dbm_open(fname, OP_RDONLY, mode);
-#else
-    if (dbmrefcnt++)
-       fatal("Old dbm can only open one database");
-    sprintf(buf,"%s.dir",fname);
-    if (stat(buf, &statbuf) < 0) {
-       if (mode < 0 || close(creat(buf,mode)) < 0)
-           return FALSE;
-       sprintf(buf,"%s.pag",fname);
-       if (close(creat(buf,mode)) < 0)
-           return FALSE;
-    }
-    xhv->xhv_dbm = dbminit(fname) >= 0;
-#endif
-#endif
-    if (!xhv->xhv_array && xhv->xhv_dbm != 0)
-       Newz(507,xhv->xhv_array, xhv->xhv_max + 1, HE*);
-    hv_magic(hv, 0, 'D');
-    return xhv->xhv_dbm != 0;
-}
-
-void
-hv_dbmclose(hv)
-HV *hv;
-{
-    register XPVHV* xhv;
-    if (!hv)
-       fatal("Bad associative array");
-    xhv = (XPVHV*)SvANY(hv);
-    if (xhv->xhv_dbm) {
-#ifdef HAS_GDBM
-       gdbm_close(xhv->xhv_dbm);
-       xhv->xhv_dbm = 0;
-#else
-#ifdef HAS_NDBM
-       dbm_close(xhv->xhv_dbm);
-       xhv->xhv_dbm = 0;
-#else
-       /* dbmrefcnt--;  */     /* doesn't work, rats */
-#endif
-#endif
-    }
-    else if (dowarn)
-       warn("Close on unopened dbm file");
-}
-
-bool
-hv_dbmstore(hv,key,klen,sv)
-HV *hv;
-char *key;
-U32 klen;
-register SV *sv;
+SV *
+hv_iternextsv(hv, key, retlen)
+    HV *hv;
+    char **key;
+    I32 *retlen;
 {
-    register XPVHV* xhv;
-    datum dkey, dcontent;
-    I32 error;
-
-    if (!hv)
-       return FALSE;
-    xhv = (XPVHV*)SvANY(hv);
-    if (!xhv->xhv_dbm)
-       return FALSE;
-    dkey.dptr = key;
-    dkey.dsize = klen;
-    dcontent.dptr = SvPVn(sv);
-    dcontent.dsize = SvCUR(sv);
-#ifdef HAS_GDBM
-    error = gdbm_store(xhv->xhv_dbm, dkey, dcontent, GDBM_REPLACE);
-#else
-    error = dbm_store(xhv->xhv_dbm, dkey, dcontent, DBM_REPLACE);
-#endif
-    if (error) {
-       if (errno == EPERM)
-           fatal("No write permission to dbm file");
-       fatal("dbm store returned %d, errno %d, key \"%s\"",error,errno,key);
-#ifdef HAS_NDBM
-        dbm_clearerr(xhv->xhv_dbm);
-#endif
-    }
-    return !error;
+    HE *he;
+    if ( (he = hv_iternext(hv)) == NULL)
+       return NULL;
+    *key = hv_iterkey(he, retlen);
+    return hv_iterval(hv, he);
 }
-#endif /* SOME_DBM */
-
-#ifdef XXX
-               magictype = MgTYPE(magic);
-               switch (magictype) {
-               case 'E':
-                   environ[0] = Nullch;
-                   break;
-               case 'S':
-#ifndef NSIG
-#define NSIG 32
-#endif
-                   for (i = 1; i < NSIG; i++)
-                       signal(i, SIG_DFL);     /* crunch, crunch, crunch */
-                   break;
-               }
-
-                   if (magic) {
-                       sv_magic(tmpstr, (SV*)tmpgv, magic, tmps, SvCUR(sv));
-                       sv_magicset(tmpstr, magic);
-                   }
-
-       if (hv->hv_sv.sv_rare && !sv->sv_magic)
-           sv_magic(sv, (GV*)hv, hv->hv_sv.sv_rare, key, keylen);
-#endif
 
 void
 hv_magic(hv, gv, how)
 HV* hv;
 GV* gv;
-I32 how;
+int how;
 {
-    sv_magic(hv, gv, how, 0, 0);
+    sv_magic((SV*)hv, (SV*)gv, how, Nullch, 0);
 }