Integrate mainline as of _55
[p5sagit/p5-mst-13.2.git] / hv.c
diff --git a/hv.c b/hv.c
index 806e573..e495e91 100644 (file)
--- a/hv.c
+++ b/hv.c
@@ -1,6 +1,6 @@
 /*    hv.c
  *
- *    Copyright (c) 1991-1994, Larry Wall
+ *    Copyright (c) 1991-1997, 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.
 static void hsplit _((HV *hv));
 static void hfreeentries _((HV *hv));
 
-static HE* more_he();
+static HE* more_he(void);
 
 static HE*
-new_he()
+new_he(void)
 {
     HE* he;
     if (he_root) {
@@ -32,15 +32,14 @@ new_he()
 }
 
 static void
-del_he(p)
-HE* p;
+del_he(HE *p)
 {
     HeNEXT(p) = (HE*)he_root;
     he_root = p;
 }
 
 static HE*
-more_he()
+more_he(void)
 {
     register HE* he;
     register HE* heend;
@@ -56,10 +55,7 @@ more_he()
 }
 
 static HEK *
-save_hek(str, len, hash)
-char *str;
-I32 len;
-U32 hash;
+save_hek(char *str, I32 len, U32 hash)
 {
     char *k;
     register HEK *hek;
@@ -74,8 +70,7 @@ U32 hash;
 }
 
 void
-unshare_hek(hek)
-HEK *hek;
+unshare_hek(HEK *hek)
 {
     unsharepvn(HEK_KEY(hek),HEK_LEN(hek),HEK_HASH(hek));
 }
@@ -84,11 +79,7 @@ HEK *hek;
  * contains an SV* */
 
 SV**
-hv_fetch(hv,key,klen,lval)
-HV *hv;
-char *key;
-U32 klen;
-I32 lval;
+hv_fetch(HV *hv, char *key, U32 klen, I32 lval)
 {
     register XPVHV* xhv;
     register U32 hash;
@@ -100,6 +91,7 @@ I32 lval;
 
     if (SvRMAGICAL(hv)) {
        if (mg_find((SV*)hv,'P')) {
+           dTHR;
            sv = sv_newmortal();
            mg_copy((SV*)hv, sv, key, klen);
            Sv = sv;
@@ -135,9 +127,9 @@ I32 lval;
     if (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME)) {
       char *gotenv;
 
-      gotenv = my_getenv(key);
-      if (gotenv != NULL) {
+      if ((gotenv = ENV_getenv(key)) != Nullch) {
         sv = newSVpv(gotenv,strlen(gotenv));
+        SvTAINTED_on(sv);
         return hv_store(hv,key,klen,sv,hash);
       }
     }
@@ -152,11 +144,7 @@ I32 lval;
 /* returns a HE * structure with the all fields set */
 /* note that hent_val will be a mortal sv for MAGICAL hashes */
 HE *
-hv_fetch_ent(hv,keysv,lval,hash)
-HV *hv;
-SV *keysv;
-I32 lval;
-register U32 hash;
+hv_fetch_ent(HV *hv, SV *keysv, I32 lval, register U32 hash)
 {
     register XPVHV* xhv;
     register char *key;
@@ -177,7 +165,6 @@ register U32 hash;
            char *k;
            New(54, k, HEK_BASESIZE + sizeof(SV*), char);
            HeKEY_hek(&mh) = (HEK*)k;
-           HeKLEN(&mh) = HEf_SVKEY;    /* key will always hold an SV* */
        }
        HeSVKEY_set(&mh, keysv);
        HeVAL(&mh) = sv;
@@ -215,9 +202,9 @@ register U32 hash;
     if (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME)) {
       char *gotenv;
 
-      gotenv = my_getenv(key);
-      if (gotenv != NULL) {
+      if ((gotenv = ENV_getenv(key)) != Nullch) {
         sv = newSVpv(gotenv,strlen(gotenv));
+        SvTAINTED_on(sv);
         return hv_store_ent(hv,keysv,sv,hash);
       }
     }
@@ -229,13 +216,31 @@ register U32 hash;
     return 0;
 }
 
-SV**
-hv_store(hv,key,klen,val,hash)
+static void
+hv_magic_check (hv, needs_copy, needs_store)
 HV *hv;
-char *key;
-U32 klen;
-SV *val;
-register U32 hash;
+bool *needs_copy;
+bool *needs_store;
+{
+    MAGIC *mg = SvMAGIC(hv);
+    *needs_copy = FALSE;
+    *needs_store = TRUE;
+    while (mg) {
+       if (isUPPER(mg->mg_type)) {
+           *needs_copy = TRUE;
+           switch (mg->mg_type) {
+           case 'P':
+           case 'I':
+           case 'S':
+               *needs_store = FALSE;
+           }
+       }
+       mg = mg->mg_moremagic;
+    }
+}
+
+SV**
+hv_store(HV *hv, char *key, U32 klen, SV *val, register U32 hash)
 {
     register XPVHV* xhv;
     register I32 i;
@@ -247,15 +252,14 @@ register U32 hash;
 
     xhv = (XPVHV*)SvANY(hv);
     if (SvMAGICAL(hv)) {
-       mg_copy((SV*)hv, val, key, klen);
-       if (!xhv->xhv_array
-           && (SvMAGIC(hv)->mg_moremagic
-               || (SvMAGIC(hv)->mg_type != 'E'
-#ifdef OVERLOAD
-                   && SvMAGIC(hv)->mg_type != 'A'
-#endif /* OVERLOAD */
-                   )))
-           return 0;
+       bool needs_copy;
+       bool needs_store;
+       hv_magic_check (hv, &needs_copy, &needs_store);
+       if (needs_copy) {
+           mg_copy((SV*)hv, val, key, klen);
+           if (!xhv->xhv_array && !needs_store)
+               return 0;
+       }
     }
     if (!hash)
        PERL_HASH(hash, key, klen);
@@ -298,11 +302,7 @@ register U32 hash;
 }
 
 HE *
-hv_store_ent(hv,keysv,val,hash)
-HV *hv;
-SV *keysv;
-SV *val;
-register U32 hash;
+hv_store_ent(HV *hv, SV *keysv, SV *val, register U32 hash)
 {
     register XPVHV* xhv;
     register char *key;
@@ -316,16 +316,20 @@ register U32 hash;
 
     xhv = (XPVHV*)SvANY(hv);
     if (SvMAGICAL(hv)) {
-       keysv = sv_2mortal(newSVsv(keysv));
-       mg_copy((SV*)hv, val, (char*)keysv, HEf_SVKEY);
-       if (!xhv->xhv_array
-           && (SvMAGIC(hv)->mg_moremagic
-               || (SvMAGIC(hv)->mg_type != 'E'
-#ifdef OVERLOAD
-                   && SvMAGIC(hv)->mg_type != 'A'
-#endif /* OVERLOAD */
-                   )))
-         return Nullhe;
+       dTHR;
+       bool needs_copy;
+       bool needs_store;
+       hv_magic_check (hv, &needs_copy, &needs_store);
+       if (needs_copy) {
+           bool save_taint = tainted;
+           if (tainting)
+               tainted = SvTAINTED(keysv);
+           keysv = sv_2mortal(newSVsv(keysv));
+           mg_copy((SV*)hv, val, (char*)keysv, HEf_SVKEY);
+           TAINT_IF(save_taint);
+           if (!xhv->xhv_array && !needs_store)
+               return Nullhe;
+       }
     }
 
     key = SvPV(keysv, klen);
@@ -371,11 +375,7 @@ register U32 hash;
 }
 
 SV *
-hv_delete(hv,key,klen,flags)
-HV *hv;
-char *key;
-U32 klen;
-I32 flags;
+hv_delete(HV *hv, char *key, U32 klen, I32 flags)
 {
     register XPVHV* xhv;
     register I32 i;
@@ -423,7 +423,7 @@ I32 flags;
        if (entry == xhv->xhv_eiter)
            HvLAZYDEL_on(hv);
        else
-           he_free(entry, HvSHAREKEYS(hv));
+           hv_free_ent(hv, entry);
        --xhv->xhv_keys;
        return sv;
     }
@@ -431,11 +431,7 @@ I32 flags;
 }
 
 SV *
-hv_delete_ent(hv,keysv,flags,hash)
-HV *hv;
-SV *keysv;
-I32 flags;
-U32 hash;
+hv_delete_ent(HV *hv, SV *keysv, I32 flags, U32 hash)
 {
     register XPVHV* xhv;
     register I32 i;
@@ -485,7 +481,7 @@ U32 hash;
        if (entry == xhv->xhv_eiter)
            HvLAZYDEL_on(hv);
        else
-           he_free(entry, HvSHAREKEYS(hv));
+           hv_free_ent(hv, entry);
        --xhv->xhv_keys;
        return sv;
     }
@@ -493,10 +489,7 @@ U32 hash;
 }
 
 bool
-hv_exists(hv,key,klen)
-HV *hv;
-char *key;
-U32 klen;
+hv_exists(HV *hv, char *key, U32 klen)
 {
     register XPVHV* xhv;
     register U32 hash;
@@ -508,6 +501,7 @@ U32 klen;
 
     if (SvRMAGICAL(hv)) {
        if (mg_find((SV*)hv,'P')) {
+           dTHR;
            sv = sv_newmortal();
            mg_copy((SV*)hv, sv, key, klen); 
            magic_existspack(sv, mg_find(sv, 'p'));
@@ -536,10 +530,7 @@ U32 klen;
 
 
 bool
-hv_exists_ent(hv,keysv,hash)
-HV *hv;
-SV *keysv;
-U32 hash;
+hv_exists_ent(HV *hv, SV *keysv, U32 hash)
 {
     register XPVHV* xhv;
     register char *key;
@@ -552,6 +543,7 @@ U32 hash;
 
     if (SvRMAGICAL(hv)) {
        if (mg_find((SV*)hv,'P')) {
+           dTHR;               /* just for SvTRUE */
            sv = sv_newmortal();
            keysv = sv_2mortal(newSVsv(keysv));
            mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY); 
@@ -582,8 +574,7 @@ U32 hash;
 }
 
 static void
-hsplit(hv)
-HV *hv;
+hsplit(HV *hv)
 {
     register XPVHV* xhv = (XPVHV*)SvANY(hv);
     I32 oldsize = (I32) xhv->xhv_max + 1; /* sic(k) */
@@ -612,9 +603,9 @@ HV *hv;
     assert(tmp >= newsize);
     New(2,a, tmp, HE*);
     Copy(xhv->xhv_array, a, oldsize, HE*);
-    if (oldsize >= 64 && !nice_chunk) {
-       nice_chunk = (char*)xhv->xhv_array;
-       nice_chunk_size = oldsize * sizeof(HE*) * 2 - MALLOC_OVERHEAD;
+    if (oldsize >= 64) {
+       offer_nice_chunk(xhv->xhv_array,
+                        oldsize * sizeof(HE*) * 2 - MALLOC_OVERHEAD);
     }
     else
        Safefree(xhv->xhv_array);
@@ -647,9 +638,7 @@ HV *hv;
 }
 
 void
-hv_ksplit(hv, newmax)
-HV *hv;
-IV newmax;
+hv_ksplit(HV *hv, IV newmax)
 {
     register XPVHV* xhv = (XPVHV*)SvANY(hv);
     I32 oldsize = (I32) xhv->xhv_max + 1; /* sic(k) */
@@ -686,9 +675,9 @@ IV newmax;
        assert(j >= newsize);
        New(2, a, j, HE*);
        Copy(xhv->xhv_array, a, oldsize, HE*);
-       if (oldsize >= 64 && !nice_chunk) {
-           nice_chunk = (char*)xhv->xhv_array;
-           nice_chunk_size = oldsize * sizeof(HE*) * 2 - MALLOC_OVERHEAD;
+       if (oldsize >= 64) {
+           offer_nice_chunk(xhv->xhv_array,
+                            oldsize * sizeof(HE*) * 2 - MALLOC_OVERHEAD);
        }
        else
            Safefree(xhv->xhv_array);
@@ -725,7 +714,7 @@ IV newmax;
 }
 
 HV *
-newHV()
+newHV(void)
 {
     register HV *hv;
     register XPVHV* xhv;
@@ -746,46 +735,45 @@ newHV()
 }
 
 void
-he_free(hent, shared)
-register HE *hent;
-I32 shared;
+hv_free_ent(HV *hv, register HE *entry)
 {
-    if (!hent)
+    if (!entry)
        return;
-    if (SvTYPE(HeVAL(hent)) == SVt_PVGV)
-       sub_generation++;               /* May be deletion of method? */
-    SvREFCNT_dec(HeVAL(hent));
-    if (HeKLEN(hent) == HEf_SVKEY) {
-       SvREFCNT_dec(HeKEY_sv(hent));
-        Safefree(HeKEY_hek(hent));
-    } else if (shared)
-       unshare_hek(HeKEY_hek(hent));
+    if (isGV(HeVAL(entry)) && GvCVu(HeVAL(entry)) && HvNAME(hv))
+       sub_generation++;       /* may be deletion of method from stash */
+    SvREFCNT_dec(HeVAL(entry));
+    if (HeKLEN(entry) == HEf_SVKEY) {
+       SvREFCNT_dec(HeKEY_sv(entry));
+        Safefree(HeKEY_hek(entry));
+    }
+    else if (HvSHAREKEYS(hv))
+       unshare_hek(HeKEY_hek(entry));
     else
-       Safefree(HeKEY_hek(hent));
-    del_he(hent);
+       Safefree(HeKEY_hek(entry));
+    del_he(entry);
 }
 
 void
-he_delayfree(hent, shared)
-register HE *hent;
-I32 shared;
+hv_delayfree_ent(HV *hv, register HE *entry)
 {
-    if (!hent)
+    if (!entry)
        return;
-    sv_2mortal(HeVAL(hent));   /* free between statements */
-    if (HeKLEN(hent) == HEf_SVKEY) {
-       sv_2mortal(HeKEY_sv(hent));
-       Safefree(HeKEY_hek(hent));
-    } else if (shared)
-       unshare_hek(HeKEY_hek(hent));
+    if (isGV(HeVAL(entry)) && GvCVu(HeVAL(entry)) && HvNAME(hv))
+       sub_generation++;       /* may be deletion of method from stash */
+    sv_2mortal(HeVAL(entry));  /* free between statements */
+    if (HeKLEN(entry) == HEf_SVKEY) {
+       sv_2mortal(HeKEY_sv(entry));
+       Safefree(HeKEY_hek(entry));
+    }
+    else if (HvSHAREKEYS(hv))
+       unshare_hek(HeKEY_hek(entry));
     else
-       Safefree(HeKEY_hek(hent));
-    del_he(hent);
+       Safefree(HeKEY_hek(entry));
+    del_he(entry);
 }
 
 void
-hv_clear(hv)
-HV *hv;
+hv_clear(HV *hv)
 {
     register XPVHV* xhv;
     if (!hv)
@@ -802,15 +790,13 @@ HV *hv;
 }
 
 static void
-hfreeentries(hv)
-HV *hv;
+hfreeentries(HV *hv)
 {
     register HE **array;
-    register HE *hent;
-    register HE *ohent = Null(HE*);
+    register HE *entry;
+    register HE *oentry = Null(HE*);
     I32 riter;
     I32 max;
-    I32 shared;
 
     if (!hv)
        return;
@@ -820,26 +806,24 @@ HV *hv;
     riter = 0;
     max = HvMAX(hv);
     array = HvARRAY(hv);
-    hent = array[0];
-    shared = HvSHAREKEYS(hv);
+    entry = array[0];
     for (;;) {
-       if (hent) {
-           ohent = hent;
-           hent = HeNEXT(hent);
-           he_free(ohent, shared);
+       if (entry) {
+           oentry = entry;
+           entry = HeNEXT(entry);
+           hv_free_ent(hv, oentry);
        }
-       if (!hent) {
+       if (!entry) {
            if (++riter > max)
                break;
-           hent = array[riter];
+           entry = array[riter];
        } 
     }
     (void)hv_iterinit(hv);
 }
 
 void
-hv_undef(hv)
-HV *hv;
+hv_undef(HV *hv)
 {
     register XPVHV* xhv;
     if (!hv)
@@ -852,7 +836,7 @@ HV *hv;
        HvNAME(hv) = 0;
     }
     xhv->xhv_array = 0;
-    xhv->xhv_max = 7;          /* it's a normal associative array */
+    xhv->xhv_max = 7;          /* it's a normal hash */
     xhv->xhv_fill = 0;
     xhv->xhv_keys = 0;
 
@@ -861,26 +845,30 @@ HV *hv;
 }
 
 I32
-hv_iterinit(hv)
-HV *hv;
+hv_iterinit(HV *hv)
 {
-    register XPVHV* xhv = (XPVHV*)SvANY(hv);
-    HE *entry = xhv->xhv_eiter;
+    register XPVHV* xhv;
+    HE *entry;
+
+    if (!hv)
+       croak("Bad hash");
+    xhv = (XPVHV*)SvANY(hv);
+    entry = xhv->xhv_eiter;
 #ifdef DYNAMIC_ENV_FETCH  /* set up %ENV for iteration */
-    if (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME)) prime_env_iter();
+    if (HvNAME(hv) && strEQ(HvNAME(hv), ENV_HV_NAME))
+       prime_env_iter();
 #endif
     if (entry && HvLAZYDEL(hv)) {      /* was deleted earlier? */
        HvLAZYDEL_off(hv);
-       he_free(entry, HvSHAREKEYS(hv));
+       hv_free_ent(hv, entry);
     }
     xhv->xhv_riter = -1;
     xhv->xhv_eiter = Null(HE*);
-    return xhv->xhv_fill;
+    return xhv->xhv_fill;      /* should be xhv->xhv_keys? May change later */
 }
 
 HE *
-hv_iternext(hv)
-HV *hv;
+hv_iternext(HV *hv)
 {
     register XPVHV* xhv;
     register HE *entry;
@@ -888,7 +876,7 @@ HV *hv;
     MAGIC* mg;
 
     if (!hv)
-       croak("Bad associative array");
+       croak("Bad hash");
     xhv = (XPVHV*)SvANY(hv);
     oldentry = entry = xhv->xhv_eiter;
 
@@ -938,7 +926,7 @@ HV *hv;
 
     if (oldentry && HvLAZYDEL(hv)) {           /* was deleted earlier? */
        HvLAZYDEL_off(hv);
-       he_free(oldentry, HvSHAREKEYS(hv));
+       hv_free_ent(hv, oldentry);
     }
 
     xhv->xhv_eiter = entry;
@@ -946,12 +934,13 @@ HV *hv;
 }
 
 char *
-hv_iterkey(entry,retlen)
-register HE *entry;
-I32 *retlen;
+hv_iterkey(register HE *entry, I32 *retlen)
 {
     if (HeKLEN(entry) == HEf_SVKEY) {
-       return SvPV(HeKEY_sv(entry), *(STRLEN*)retlen);
+       STRLEN len;
+       char *p = SvPV(HeKEY_sv(entry), len);
+       *retlen = len;
+       return p;
     }
     else {
        *retlen = HeKLEN(entry);
@@ -961,8 +950,7 @@ I32 *retlen;
 
 /* unlike hv_iterval(), this always returns a mortal copy of the key */
 SV *
-hv_iterkeysv(entry)
-register HE *entry;
+hv_iterkeysv(register HE *entry)
 {
     if (HeKLEN(entry) == HEf_SVKEY)
        return sv_mortalcopy(HeKEY_sv(entry));
@@ -972,9 +960,7 @@ register HE *entry;
 }
 
 SV *
-hv_iterval(hv,entry)
-HV *hv;
-register HE *entry;
+hv_iterval(HV *hv, register HE *entry)
 {
     if (SvRMAGICAL(hv)) {
        if (mg_find((SV*)hv,'P')) {
@@ -989,10 +975,7 @@ register HE *entry;
 }
 
 SV *
-hv_iternextsv(hv, key, retlen)
-    HV *hv;
-    char **key;
-    I32 *retlen;
+hv_iternextsv(HV *hv, char **key, I32 *retlen)
 {
     HE *he;
     if ( (he = hv_iternext(hv)) == NULL)
@@ -1002,19 +985,13 @@ hv_iternextsv(hv, key, retlen)
 }
 
 void
-hv_magic(hv, gv, how)
-HV* hv;
-GV* gv;
-int how;
+hv_magic(HV *hv, GV *gv, int how)
 {
     sv_magic((SV*)hv, (SV*)gv, how, Nullch, 0);
 }
 
 char*  
-sharepvn(sv, len, hash)
-char* sv;
-I32 len;
-U32 hash;
+sharepvn(char *sv, I32 len, U32 hash)
 {
     return HEK_KEY(share_hek(sv, len, hash));
 }
@@ -1023,10 +1000,7 @@ U32 hash;
  * len and hash must both be valid for str.
  */
 void
-unsharepvn(str, len, hash)
-char* str;
-I32 len;
-U32 hash;
+unsharepvn(char *str, I32 len, U32 hash)
 {
     register XPVHV* xhv;
     register HE *entry;
@@ -1070,10 +1044,7 @@ U32 hash;
  * len and hash must both be valid for str.
  */
 HEK *
-share_hek(str, len, hash)
-char *str;
-I32 len;
-register U32 hash;
+share_hek(char *str, I32 len, register U32 hash)
 {
     register XPVHV* xhv;
     register HE *entry;