-/*
-=for apidoc hv_fetch
-
-Returns the SV which corresponds to the specified key in the hash. The
-C<klen> is the length of the key. If C<lval> is set then the fetch will be
-part of a store. Check that the return value is non-null before
-dereferencing it to an C<SV*>.
-
-See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for more
-information on how to use this function on tied hashes.
-
-=cut
-*/
-
-#define HV_FETCH_LVALUE 0x01
-#define HV_FETCH_JUST_SV 0x02
-
-SV**
-Perl_hv_fetch(pTHX_ HV *hv, const char *key, I32 klen, I32 lval)
-{
- HE *hek = hv_fetch_common (hv, NULL, key, klen, 0,
- HV_FETCH_JUST_SV | (lval ? HV_FETCH_LVALUE : 0),
- 0);
- return hek ? &HeVAL(hek) : NULL;
-}
-
-/* returns an HE * structure with the all fields set */
-/* note that hent_val will be a mortal sv for MAGICAL hashes */
-/*
-=for apidoc hv_fetch_ent
-
-Returns the hash entry which corresponds to the specified key in the hash.
-C<hash> must be a valid precomputed hash number for the given C<key>, or 0
-if you want the function to compute it. IF C<lval> is set then the fetch
-will be part of a store. Make sure the return value is non-null before
-accessing it. The return value when C<tb> is a tied hash is a pointer to a
-static location, so be sure to make a copy of the structure if you need to
-store it somewhere.
-
-See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for more
-information on how to use this function on tied hashes.
-
-=cut
-*/
-
-HE *
-Perl_hv_fetch_ent(pTHX_ HV *hv, SV *keysv, I32 lval, register U32 hash)
-{
- return hv_fetch_common(hv, keysv, NULL, 0, 0, lval ? HV_FETCH_LVALUE : 0,
- hash);
-}
-
-HE *
-S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, I32 klen_i32,
- int flags, int action, register U32 hash)
-{
- register XPVHV* xhv;
- STRLEN klen;
- register HE *entry;
- SV *sv;
- bool is_utf8;
- const char *keysave;
- int masked_flags;
-
- if (!hv)
- return 0;
-
- if (keysv) {
- key = SvPV(keysv, klen);
- is_utf8 = (SvUTF8(keysv) != 0);
- } else {
- if (klen_i32 < 0) {
- klen = -klen_i32;
- is_utf8 = TRUE;
- } else {
- klen = klen_i32;
- is_utf8 = FALSE;
- }
- }
- keysave = key;
-
- if (SvRMAGICAL(hv)) {
- if (mg_find((SV*)hv, PERL_MAGIC_tied) || SvGMAGICAL((SV*)hv)) {
- sv = sv_newmortal();
-
- /* XXX should be able to skimp on the HE/HEK here when
- HV_FETCH_JUST_SV is true. */
-
- if (!keysv) {
- keysv = newSVpvn(key, klen);
- if (is_utf8) {
- SvUTF8_on(keysv);
- }
- } else {
- keysv = newSVsv(keysv);
- }
- mg_copy((SV*)hv, sv, (char *)keysv, HEf_SVKEY);
-
-
- /* grab a fake HE/HEK pair from the pool or make a new one */
- entry = PL_hv_fetch_ent_mh;
- if (entry)
- PL_hv_fetch_ent_mh = HeNEXT(entry);
- else {
- char *k;
- entry = new_HE();
- New(54, k, HEK_BASESIZE + sizeof(SV*), char);
- HeKEY_hek(entry) = (HEK*)k;
- }
- HeNEXT(entry) = Nullhe;
- HeSVKEY_set(entry, keysv);
- HeVAL(entry) = sv;
- sv_upgrade(sv, SVt_PVLV);
- LvTYPE(sv) = 'T';
- LvTARG(sv) = (SV*)entry; /* so we can free entry when freeing sv */
-
- /* XXX remove at some point? */
- if (flags & HVhek_FREEKEY)
- Safefree(key);
-
- return entry;
- }
-#ifdef ENV_IS_CASELESS
- else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
- U32 i;
- for (i = 0; i < klen; ++i)
- if (isLOWER(key[i])) {
- SV *nkeysv = sv_2mortal(newSVpvn(key,klen));
- (void)strupr(SvPVX(nkeysv));
- entry = hv_fetch_common(hv, nkeysv, NULL, 0, 0, 0);
- if (!entry && (action & HV_FETCH_LVALUE))
- entry = hv_store_ent(hv, keysv, NEWSV(61,0), hash);
-
- /* XXX remove at some point? */
- if (flags & HVhek_FREEKEY)
- Safefree(key);
-
- return entry;
- }
- }
-#endif
- }
-
- xhv = (XPVHV*)SvANY(hv);
- if (!xhv->xhv_array /* !HvARRAY(hv) */) {
- if ((action & HV_FETCH_LVALUE)
-#ifdef DYNAMIC_ENV_FETCH /* if it's an %ENV lookup, we may get it on the fly */
- || (SvRMAGICAL((SV*)hv) && mg_find((SV*)hv, PERL_MAGIC_env))
-#endif
- )
- Newz(503, xhv->xhv_array /* HvARRAY(hv) */,
- PERL_HV_ARRAY_ALLOC_BYTES(xhv->xhv_max+1 /* HvMAX(hv)+1 */),
- char);
- else {
- /* XXX remove at some point? */
- if (flags & HVhek_FREEKEY)
- Safefree(key);
-
- return 0;
- }
- }
-
- if (is_utf8) {
- int oldflags = flags;
- key = (char*)bytes_from_utf8((U8*)key, &klen, &is_utf8);
- if (is_utf8)
- flags = HVhek_UTF8;
- if (key != keysave)
- flags |= HVhek_WASUTF8 | HVhek_FREEKEY;
- if (oldflags & HVhek_FREEKEY)
- Safefree(keysave);
-
- }
-
- if (HvREHASH(hv)) {
- PERL_HASH_INTERNAL(hash, key, klen);
- /* Yes, you do need this even though you are not "storing" because
- you can flip the flags below if doing an lval lookup. (And that
- was put in to give the semantics Andreas was expecting.) */
- flags |= HVhek_REHASH;
- } else if (!hash) {
- if (keysv && (SvIsCOW_shared_hash(keysv))) {
- hash = SvUVX(keysv);
- } else {
- PERL_HASH(hash, key, klen);
- }
- }
-
- masked_flags = (flags & HVhek_MASK);
-
- /* entry = (HvARRAY(hv))[hash & (I32) HvMAX(hv)]; */
- entry = ((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max];
- for (; entry; entry = HeNEXT(entry)) {
- if (HeHASH(entry) != hash) /* strings can't be equal */
- continue;
- if (HeKLEN(entry) != (I32)klen)
- continue;
- if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen)) /* is this it? */
- continue;
- if ((HeKFLAGS(entry) ^ masked_flags) & HVhek_UTF8)
- continue;
- if ((action & HV_FETCH_LVALUE) && HeKFLAGS(entry) != masked_flags) {
- /* We match if HVhek_UTF8 bit in our flags and hash key's match.
- But if entry was set previously with HVhek_WASUTF8 and key now
- doesn't (or vice versa) then we should change the key's flag,
- as this is assignment. */
- if (HvSHAREKEYS(hv)) {
- /* Need to swap the key we have for a key with the flags we
- need. As keys are shared we can't just write to the flag,
- so we share the new one, unshare the old one. */
- HEK *new_hek = share_hek_flags(key, klen, hash, masked_flags);
- unshare_hek (HeKEY_hek(entry));
- HeKEY_hek(entry) = new_hek;
- }
- else
- HeKFLAGS(entry) = masked_flags;
- if (masked_flags & HVhek_ENABLEHVKFLAGS)
- HvHASKFLAGS_on(hv);
- }
- /* if we find a placeholder, we pretend we haven't found anything */
- if (HeVAL(entry) == &PL_sv_placeholder)
- break;
- if (flags & HVhek_FREEKEY)
- Safefree(key);
- return entry;
- }
-#ifdef DYNAMIC_ENV_FETCH /* %ENV lookup? If so, try to fetch the value now */
- if (SvRMAGICAL((SV*)hv) && mg_find((SV*)hv, PERL_MAGIC_env)) {
- unsigned long len;
- char *env = PerlEnv_ENVgetenv_len(key,&len);
- if (env) {
- /* XXX remove once common API complete */
- if (!keysv) {
- nkeysv = sv_2mortal(newSVpvn(key,klen));
- }
-
- sv = newSVpvn(env,len);
- SvTAINTED_on(sv);
- if (flags & HVhek_FREEKEY)
- Safefree(key);
- return hv_store_ent(hv,keysv,sv,hash);
- }
- }
-#endif
- if (!entry && SvREADONLY(hv)) {
- S_hv_notallowed(aTHX_ flags, key, klen,
- "access disallowed key '%"SVf"' in"
- );
- }
- if (action & HV_FETCH_LVALUE) {
- /* XXX remove once common API complete */
- if (!keysv) {
- keysv = sv_2mortal(newSVpvn(key,klen));
- }
- }
-
- if (flags & HVhek_FREEKEY)
- Safefree(key);
- if (action & HV_FETCH_LVALUE) {
- /* gonna assign to this, so it better be there */
- sv = NEWSV(61,0);
- return hv_store_ent(hv,keysv,sv,hash);
- }
- return 0;
-}
-
-STATIC void
-S_hv_magic_check(pTHX_ HV *hv, 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 PERL_MAGIC_tied:
- case PERL_MAGIC_sig:
- *needs_store = FALSE;
- }
- }
- mg = mg->mg_moremagic;
- }
-}