diff options
Diffstat (limited to 'sv.c')
-rw-r--r-- | sv.c | 2046 |
1 files changed, 2046 insertions, 0 deletions
@@ -0,0 +1,2046 @@ +/* $RCSfile: sv.c,v $$Revision: 4.1 $$Date: 92/08/07 18:26:45 $ + * + * Copyright (c) 1991, 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: sv.c,v $ + * Revision 4.1 92/08/07 18:26:45 lwall + * + * Revision 4.0.1.6 92/06/11 21:14:21 lwall + * patch34: quotes containing subscripts containing variables didn't parse right + * + * Revision 4.0.1.5 92/06/08 15:40:43 lwall + * patch20: removed implicit int declarations on functions + * patch20: Perl now distinguishes overlapped copies from non-overlapped + * patch20: paragraph mode now skips extra newlines automatically + * patch20: fixed memory leak in doube-quote interpretation + * patch20: made /\$$foo/ look for literal '$foo' + * patch20: "$var{$foo'bar}" didn't scan subscript correctly + * patch20: a splice on non-existent array elements could dump core + * patch20: running taintperl explicitly now does checks even if $< == $> + * + * Revision 4.0.1.4 91/11/05 18:40:51 lwall + * patch11: $foo .= <BAR> could overrun malloced memory + * patch11: \$ didn't always make it through double-quoter to regexp routines + * patch11: prepared for ctype implementations that don't define isascii() + * + * Revision 4.0.1.3 91/06/10 01:27:54 lwall + * patch10: $) and $| incorrectly handled in run-time patterns + * + * Revision 4.0.1.2 91/06/07 11:58:13 lwall + * patch4: new copyright notice + * patch4: taint check on undefined string could cause core dump + * + * Revision 4.0.1.1 91/04/12 09:15:30 lwall + * patch1: fixed undefined environ problem + * patch1: substr($ENV{"PATH"},0,0) = "/foo:" didn't modify environment + * patch1: $foo .= <BAR> could cause core dump for certain lengths of $foo + * + * Revision 4.0 91/03/20 01:39:55 lwall + * 4.0 baseline. + * + */ + +#include "EXTERN.h" +#include "perl.h" +#include "perly.h" + +static void ucase(); +static void lcase(); + +bool +sv_upgrade(sv, mt) +register SV* sv; +U32 mt; +{ + char* pv; + U32 cur; + U32 len; + I32 iv; + double nv; + MAGIC* magic; + HV* stash; + + if (SvTYPE(sv) == mt) + return TRUE; + + switch (SvTYPE(sv)) { + case SVt_NULL: + pv = 0; + cur = 0; + len = 0; + iv = 0; + nv = 0.0; + magic = 0; + stash = 0; + break; + case SVt_REF: + sv_free((SV*)SvANY(sv)); + pv = 0; + cur = 0; + len = 0; + iv = SvANYI32(sv); + nv = (double)SvANYI32(sv); + SvNOK_only(sv); + magic = 0; + stash = 0; + if (mt == SVt_PV) + mt = SVt_PVIV; + break; + case SVt_IV: + pv = 0; + cur = 0; + len = 0; + iv = SvIV(sv); + nv = (double)SvIV(sv); + del_XIV(SvANY(sv)); + magic = 0; + stash = 0; + if (mt == SVt_PV) + mt = SVt_PVIV; + break; + case SVt_NV: + pv = 0; + cur = 0; + len = 0; + if (SvIOK(sv)) + iv = SvIV(sv); + else + iv = (I32)SvNV(sv); + nv = SvNV(sv); + magic = 0; + stash = 0; + del_XNV(SvANY(sv)); + SvANY(sv) = 0; + if (mt == SVt_PV || mt == SVt_PVIV) + mt = SVt_PVNV; + break; + case SVt_PV: + nv = 0.0; + pv = SvPV(sv); + cur = SvCUR(sv); + len = SvLEN(sv); + iv = 0; + nv = 0.0; + magic = 0; + stash = 0; + del_XPV(SvANY(sv)); + break; + case SVt_PVIV: + nv = 0.0; + pv = SvPV(sv); + cur = SvCUR(sv); + len = SvLEN(sv); + iv = SvIV(sv); + nv = 0.0; + magic = 0; + stash = 0; + del_XPVIV(SvANY(sv)); + break; + case SVt_PVNV: + nv = SvNV(sv); + pv = SvPV(sv); + cur = SvCUR(sv); + len = SvLEN(sv); + iv = SvIV(sv); + nv = SvNV(sv); + magic = 0; + stash = 0; + del_XPVNV(SvANY(sv)); + break; + case SVt_PVMG: + pv = SvPV(sv); + cur = SvCUR(sv); + len = SvLEN(sv); + iv = SvIV(sv); + nv = SvNV(sv); + magic = SvMAGIC(sv); + stash = SvSTASH(sv); + del_XPVMG(SvANY(sv)); + break; + default: + fatal("Can't upgrade that kind of scalar"); + } + + switch (mt) { + case SVt_NULL: + fatal("Can't upgrade to undef"); + case SVt_REF: + SvIOK_on(sv); + break; + case SVt_IV: + SvANY(sv) = new_XIV(); + SvIV(sv) = iv; + break; + case SVt_NV: + SvANY(sv) = new_XNV(); + SvIV(sv) = iv; + SvNV(sv) = nv; + break; + case SVt_PV: + SvANY(sv) = new_XPV(); + SvPV(sv) = pv; + SvCUR(sv) = cur; + SvLEN(sv) = len; + break; + case SVt_PVIV: + SvANY(sv) = new_XPVIV(); + SvPV(sv) = pv; + SvCUR(sv) = cur; + SvLEN(sv) = len; + SvIV(sv) = iv; + if (SvNIOK(sv)) + SvIOK_on(sv); + SvNOK_off(sv); + break; + case SVt_PVNV: + SvANY(sv) = new_XPVNV(); + SvPV(sv) = pv; + SvCUR(sv) = cur; + SvLEN(sv) = len; + SvIV(sv) = iv; + SvNV(sv) = nv; + break; + case SVt_PVMG: + SvANY(sv) = new_XPVMG(); + SvPV(sv) = pv; + SvCUR(sv) = cur; + SvLEN(sv) = len; + SvIV(sv) = iv; + SvNV(sv) = nv; + SvMAGIC(sv) = magic; + SvSTASH(sv) = stash; + break; + case SVt_PVLV: + SvANY(sv) = new_XPVLV(); + SvPV(sv) = pv; + SvCUR(sv) = cur; + SvLEN(sv) = len; + SvIV(sv) = iv; + SvNV(sv) = nv; + SvMAGIC(sv) = magic; + SvSTASH(sv) = stash; + LvTARGOFF(sv) = 0; + LvTARGLEN(sv) = 0; + LvTARG(sv) = 0; + LvTYPE(sv) = 0; + break; + case SVt_PVAV: + SvANY(sv) = new_XPVAV(); + SvPV(sv) = pv; + SvCUR(sv) = cur; + SvLEN(sv) = len; + SvIV(sv) = iv; + SvNV(sv) = nv; + SvMAGIC(sv) = magic; + SvSTASH(sv) = stash; + AvMAGIC(sv) = 0; + AvARRAY(sv) = 0; + AvALLOC(sv) = 0; + AvMAX(sv) = 0; + AvFILL(sv) = 0; + AvARYLEN(sv) = 0; + AvFLAGS(sv) = 0; + break; + case SVt_PVHV: + SvANY(sv) = new_XPVHV(); + SvPV(sv) = pv; + SvCUR(sv) = cur; + SvLEN(sv) = len; + SvIV(sv) = iv; + SvNV(sv) = nv; + SvMAGIC(sv) = magic; + SvSTASH(sv) = stash; + HvMAGIC(sv) = 0; + HvARRAY(sv) = 0; + HvMAX(sv) = 0; + HvDOSPLIT(sv) = 0; + HvFILL(sv) = 0; + HvRITER(sv) = 0; + HvEITER(sv) = 0; + HvPMROOT(sv) = 0; + HvNAME(sv) = 0; + HvDBM(sv) = 0; + HvCOEFFSIZE(sv) = 0; + break; + case SVt_PVCV: + SvANY(sv) = new_XPVCV(); + SvPV(sv) = pv; + SvCUR(sv) = cur; + SvLEN(sv) = len; + SvIV(sv) = iv; + SvNV(sv) = nv; + SvMAGIC(sv) = magic; + SvSTASH(sv) = stash; + CvSTASH(sv) = 0; + CvSTART(sv) = 0; + CvROOT(sv) = 0; + CvUSERSUB(sv) = 0; + CvUSERINDEX(sv) = 0; + CvFILEGV(sv) = 0; + CvDEPTH(sv) = 0; + CvPADLIST(sv) = 0; + CvDELETED(sv) = 0; + break; + case SVt_PVGV: + SvANY(sv) = new_XPVGV(); + SvPV(sv) = pv; + SvCUR(sv) = cur; + SvLEN(sv) = len; + SvIV(sv) = iv; + SvNV(sv) = nv; + SvMAGIC(sv) = magic; + SvSTASH(sv) = stash; + GvNAME(sv) = 0; + GvNAMELEN(sv) = 0; + GvSTASH(sv) = 0; + break; + case SVt_PVBM: + SvANY(sv) = new_XPVBM(); + SvPV(sv) = pv; + SvCUR(sv) = cur; + SvLEN(sv) = len; + SvIV(sv) = iv; + SvNV(sv) = nv; + SvMAGIC(sv) = magic; + SvSTASH(sv) = stash; + BmRARE(sv) = 0; + BmUSEFUL(sv) = 0; + BmPREVIOUS(sv) = 0; + break; + case SVt_PVFM: + SvANY(sv) = new_XPVFM(); + SvPV(sv) = pv; + SvCUR(sv) = cur; + SvLEN(sv) = len; + SvIV(sv) = iv; + SvNV(sv) = nv; + SvMAGIC(sv) = magic; + SvSTASH(sv) = stash; + FmLINES(sv) = 0; + break; + } + SvTYPE(sv) = mt; + return TRUE; +} + +char * +sv_peek(sv) +register SV *sv; +{ + char *t = tokenbuf; + *t = '\0'; + + retry: + if (!sv) { + strcpy(t, "VOID"); + return tokenbuf; + } + else if (sv == (SV*)0x55555555 || SvTYPE(sv) == 'U') { + strcpy(t, "WILD"); + return tokenbuf; + } + else if (SvREFCNT(sv) == 0 && !SvREADONLY(sv)) { + strcpy(t, "UNREF"); + return tokenbuf; + } + else { + switch (SvTYPE(sv)) { + default: + strcpy(t,"FREED"); + return tokenbuf; + break; + + case SVt_NULL: + return "UNDEF"; + case SVt_REF: + strcpy(t, "\\"); + t += strlen(t); + sv = (SV*)SvANY(sv); + goto retry; + case SVt_IV: + strcpy(t,"IV"); + break; + case SVt_NV: + strcpy(t,"NV"); + break; + case SVt_PV: + strcpy(t,"PV"); + break; + case SVt_PVIV: + strcpy(t,"PVIV"); + break; + case SVt_PVNV: + strcpy(t,"PVNV"); + break; + case SVt_PVMG: + strcpy(t,"PVMG"); + break; + case SVt_PVLV: + strcpy(t,"PVLV"); + break; + case SVt_PVAV: + strcpy(t,"AV"); + break; + case SVt_PVHV: + strcpy(t,"HV"); + break; + case SVt_PVCV: + strcpy(t,"CV"); + break; + case SVt_PVGV: + strcpy(t,"GV"); + break; + case SVt_PVBM: + strcpy(t,"BM"); + break; + case SVt_PVFM: + strcpy(t,"FM"); + break; + } + } + t += strlen(t); + + if (SvPOK(sv)) { + if (!SvPV(sv)) + return "(null)"; + if (SvOOK(sv)) + sprintf(t,"(%d+\"%0.127s\")",SvIV(sv),SvPV(sv)); + else + sprintf(t,"(\"%0.127s\")",SvPV(sv)); + } + else if (SvNOK(sv)) + sprintf(t,"(%g)",SvNV(sv)); + else if (SvIOK(sv)) + sprintf(t,"(%ld)",(long)SvIV(sv)); + else + strcpy(t,"()"); + return tokenbuf; +} + +int +sv_backoff(sv) +register SV *sv; +{ + assert(SvOOK(sv)); + if (SvIV(sv)) { + char *s = SvPV(sv); + SvLEN(sv) += SvIV(sv); + SvPV(sv) -= SvIV(sv); + SvIV_set(sv, 0); + Move(s, SvPV(sv), SvCUR(sv)+1, char); + } + SvFLAGS(sv) &= ~SVf_OOK; +} + +char * +sv_grow(sv,newlen) +register SV *sv; +#ifndef DOSISH +register I32 newlen; +#else +unsigned long newlen; +#endif +{ + register char *s; + +#ifdef MSDOS + if (newlen >= 0x10000) { + fprintf(stderr, "Allocation too large: %lx\n", newlen); + my_exit(1); + } +#endif /* MSDOS */ + if (SvREADONLY(sv)) + fatal(no_modify); + if (SvTYPE(sv) < SVt_PV) { + sv_upgrade(sv, SVt_PV); + s = SvPV(sv); + } + else if (SvOOK(sv)) { /* pv is offset? */ + sv_backoff(sv); + s = SvPV(sv); + if (newlen > SvLEN(sv)) + newlen += 10 * (newlen - SvCUR(sv)); /* avoid copy each time */ + } + else + s = SvPV(sv); + if (newlen > SvLEN(sv)) { /* need more room? */ + if (SvLEN(sv)) + Renew(s,newlen,char); + else + New(703,s,newlen,char); + SvPV_set(sv, s); + SvLEN_set(sv, newlen); + } + return s; +} + +void +sv_setiv(sv,i) +register SV *sv; +I32 i; +{ + if (SvREADONLY(sv)) + fatal(no_modify); + if (SvTYPE(sv) < SVt_IV) + sv_upgrade(sv, SVt_IV); + else if (SvTYPE(sv) == SVt_PV) + sv_upgrade(sv, SVt_PVIV); + SvIV(sv) = i; + SvIOK_only(sv); /* validate number */ + SvTDOWN(sv); +} + +void +sv_setnv(sv,num) +register SV *sv; +double num; +{ + if (SvREADONLY(sv)) + fatal(no_modify); + if (SvTYPE(sv) < SVt_NV) + sv_upgrade(sv, SVt_NV); + else if (SvTYPE(sv) < SVt_PVNV) + sv_upgrade(sv, SVt_PVNV); + else if (SvPOK(sv)) { + SvOOK_off(sv); + } + SvNV(sv) = num; + SvNOK_only(sv); /* validate number */ + SvTDOWN(sv); +} + +I32 +sv_2iv(sv) +register SV *sv; +{ + if (!sv) + return 0; + if (SvREADONLY(sv)) { + if (SvNOK(sv)) + return (I32)SvNV(sv); + if (SvPOK(sv) && SvLEN(sv)) + return atof(SvPV(sv)); + if (dowarn) + warn("Use of uninitialized variable"); + return 0; + } + if (SvTYPE(sv) < SVt_IV) { + if (SvTYPE(sv) == SVt_REF) + return (I32)SvANYI32(sv); + sv_upgrade(sv, SVt_IV); + DEBUG_c((stderr,"0x%lx num(%g)\n",sv,SvIV(sv))); + return SvIV(sv); + } + else if (SvTYPE(sv) == SVt_PV) + sv_upgrade(sv, SVt_PVIV); + if (SvNOK(sv)) + SvIV(sv) = (I32)SvNV(sv); + else if (SvPOK(sv) && SvLEN(sv)) + SvIV(sv) = atol(SvPV(sv)); + else { + if (dowarn) + warn("Use of uninitialized variable"); + SvUPGRADE(sv, SVt_IV); + SvIV(sv) = 0; + } + SvIOK_on(sv); + DEBUG_c((stderr,"0x%lx 2iv(%d)\n",sv,SvIV(sv))); + return SvIV(sv); +} + +double +sv_2nv(sv) +register SV *sv; +{ + if (!sv) + return 0.0; + if (SvREADONLY(sv)) { + if (SvPOK(sv) && SvLEN(sv)) + return atof(SvPV(sv)); + if (dowarn) + warn("Use of uninitialized variable"); + return 0.0; + } + if (SvTYPE(sv) < SVt_NV) { + if (SvTYPE(sv) == SVt_REF) + return (double)SvANYI32(sv); + sv_upgrade(sv, SVt_NV); + DEBUG_c((stderr,"0x%lx num(%g)\n",sv,SvNV(sv))); + return SvNV(sv); + } + else if (SvTYPE(sv) < SVt_PVNV) + sv_upgrade(sv, SVt_PVNV); + if (SvPOK(sv) && SvLEN(sv)) + SvNV(sv) = atof(SvPV(sv)); + else if (SvIOK(sv)) + SvNV(sv) = (double)SvIV(sv); + else { + if (dowarn) + warn("Use of uninitialized variable"); + SvNV(sv) = 0.0; + } + SvNOK_on(sv); + DEBUG_c((stderr,"0x%lx 2nv(%g)\n",sv,SvNV(sv))); + return SvNV(sv); +} + +char * +sv_2pv(sv) +register SV *sv; +{ + register char *s; + int olderrno; + + if (!sv) + return ""; + if (SvTYPE(sv) == SVt_REF) { + sv = (SV*)SvANY(sv); + if (!sv) + return "<Empty reference>"; + switch (SvTYPE(sv)) { + case SVt_NULL: s = "an undefined value"; break; + case SVt_REF: s = "a reference"; break; + case SVt_IV: s = "an integer value"; break; + case SVt_NV: s = "a numeric value"; break; + case SVt_PV: s = "a string value"; break; + case SVt_PVIV: s = "a string+integer value"; break; + case SVt_PVNV: s = "a scalar value"; break; + case SVt_PVMG: s = "a magic value"; break; + case SVt_PVLV: s = "an lvalue"; break; + case SVt_PVAV: s = "an array value"; break; + case SVt_PVHV: s = "an associative array value"; break; + case SVt_PVCV: s = "a code value"; break; + case SVt_PVGV: s = "a glob value"; break; + case SVt_PVBM: s = "a search string"; break; + case SVt_PVFM: s = "a formatline"; break; + default: s = "something weird"; break; + } + sprintf(tokenbuf,"<Reference to %s at 0x%lx>", s, (unsigned long)sv); + return tokenbuf; + } + if (SvREADONLY(sv)) { + if (SvIOK(sv)) { + (void)sprintf(tokenbuf,"%ld",SvIV(sv)); + return tokenbuf; + } + if (SvNOK(sv)) { + (void)sprintf(tokenbuf,"%.20g",SvNV(sv)); + return tokenbuf; + } + if (dowarn) + warn("Use of uninitialized variable"); + return ""; + } + if (!SvUPGRADE(sv, SVt_PV)) + return 0; + if (SvNOK(sv)) { + if (SvTYPE(sv) < SVt_PVNV) + sv_upgrade(sv, SVt_PVNV); + SvGROW(sv, 28); + s = SvPV(sv); + olderrno = errno; /* some Xenix systems wipe out errno here */ +#if defined(scs) && defined(ns32000) + gcvt(SvNV(sv),20,s); +#else +#ifdef apollo + if (SvNV(sv) == 0.0) + (void)strcpy(s,"0"); + else +#endif /*apollo*/ + (void)sprintf(s,"%.20g",SvNV(sv)); +#endif /*scs*/ + errno = olderrno; + while (*s) s++; +#ifdef hcx + if (s[-1] == '.') + s--; +#endif + } + else if (SvIOK(sv)) { + if (SvTYPE(sv) < SVt_PVIV) + sv_upgrade(sv, SVt_PVIV); + SvGROW(sv, 11); + s = SvPV(sv); + olderrno = errno; /* some Xenix systems wipe out errno here */ + (void)sprintf(s,"%ld",SvIV(sv)); + errno = olderrno; + while (*s) s++; + } + else { + if (dowarn) + warn("Use of uninitialized variable"); + sv_grow(sv, 1); + s = SvPV(sv); + } + *s = '\0'; + SvCUR_set(sv, s - SvPV(sv)); + SvPOK_on(sv); + DEBUG_c((stderr,"0x%lx 2pv(%s)\n",sv,SvPV(sv))); + return SvPV(sv); +} + +/* Note: sv_setsv() should not be called with a source string that needs + * be reused, since it may destroy the source string if it is marked + * as temporary. + */ + +void +sv_setsv(dstr,sstr) +SV *dstr; +register SV *sstr; +{ + if (sstr == dstr) + return; + if (SvREADONLY(dstr)) + fatal(no_modify); + if (!sstr) + sstr = &sv_undef; + + if (SvTYPE(dstr) < SvTYPE(sstr)) + sv_upgrade(dstr, SvTYPE(sstr)); + else if (SvTYPE(dstr) == SVt_PV && SvTYPE(sstr) <= SVt_NV) { + if (SvTYPE(sstr) <= SVt_IV) + sv_upgrade(dstr, SVt_PVIV); /* handle discontinuities */ + else + sv_upgrade(dstr, SVt_PVNV); + } + else if (SvTYPE(dstr) == SVt_PVIV && SvTYPE(sstr) == SVt_NV) + sv_upgrade(dstr, SVt_PVNV); + + switch (SvTYPE(sstr)) { + case SVt_NULL: + if (SvTYPE(dstr) == SVt_REF) { + sv_free((SV*)SvANY(dstr)); + SvANY(dstr) = 0; + SvTYPE(dstr) = SVt_NULL; + } + else + SvOK_off(dstr); + return; + case SVt_REF: + SvTUP(sstr); + if (SvTYPE(dstr) == SVt_REF) { + SvANY(dstr) = (void*)sv_ref((SV*)SvANY(sstr)); + } + else { + if (SvMAGICAL(dstr)) + fatal("Can't assign a reference to a magical variable"); + sv_clear(dstr); + SvTYPE(dstr) = SVt_REF; + SvANY(dstr) = (void*)sv_ref((SV*)SvANY(sstr)); + SvOK_off(dstr); + } + SvTDOWN(sstr); + return; + case SVt_PVGV: + SvTUP(sstr); + if (SvTYPE(dstr) == SVt_PVGV) { + SvOK_off(dstr); + if (!GvAV(sstr)) + gv_AVadd(sstr); + if (!GvHV(sstr)) + gv_HVadd(sstr); + if (!GvIO(sstr)) + GvIO(sstr) = newIO(); + if (GvGP(dstr)) + gp_free(dstr); + GvGP(dstr) = gp_ref(GvGP(sstr)); + SvTDOWN(sstr); + return; + } + /* FALL THROUGH */ + + default: + if (SvMAGICAL(sstr)) + mg_get(sstr); + /* XXX */ + break; + } + + SvPRIVATE(dstr) = SvPRIVATE(sstr); + SvSTORAGE(dstr) = SvSTORAGE(sstr); + + if (SvPOK(sstr)) { + + SvTUP(sstr); + + /* + * Check to see if we can just swipe the string. If so, it's a + * possible small lose on short strings, but a big win on long ones. + * It might even be a win on short strings if SvPV(dstr) + * has to be allocated and SvPV(sstr) has to be freed. + */ + + if (SvTEMP(sstr)) { /* slated for free anyway? */ + if (SvPOK(dstr)) { + SvOOK_off(dstr); + Safefree(SvPV(dstr)); + } + SvPV_set(dstr, SvPV(sstr)); + SvLEN_set(dstr, SvLEN(sstr)); + SvCUR_set(dstr, SvCUR(sstr)); + SvTYPE(dstr) = SvTYPE(sstr); + SvPOK_only(dstr); + SvTEMP_off(dstr); + SvPV_set(sstr, Nullch); + SvLEN_set(sstr, 0); + SvPOK_off(sstr); /* wipe out any weird flags */ + SvTYPE(sstr) = 0; /* so sstr frees uneventfully */ + } + else { /* have to copy actual string */ + if (SvPV(dstr)) { /* XXX ck type */ + SvOOK_off(dstr); + } + sv_setpvn(dstr,SvPV(sstr),SvCUR(sstr)); + } + /*SUPPRESS 560*/ + if (SvNOK(sstr)) { + SvNOK_on(dstr); + SvNV(dstr) = SvNV(sstr); + } + if (SvIOK(sstr)) { + SvIOK_on(dstr); + SvIV(dstr) = SvIV(sstr); + } + } + else if (SvNOK(sstr)) { + SvTUP(sstr); + SvNV(dstr) = SvNV(sstr); + SvNOK_only(dstr); + if (SvIOK(sstr)) { + SvIOK_on(dstr); + SvIV(dstr) = SvIV(sstr); + } + } + else if (SvIOK(sstr)) { + SvTUP(sstr); + SvIOK_only(dstr); + SvIV(dstr) = SvIV(sstr); + } + else { + SvTUP(sstr); + SvOK_off(dstr); + } + SvTDOWN(dstr); +} + +void +sv_setpvn(sv,ptr,len) +register SV *sv; +register char *ptr; +register STRLEN len; +{ + if (!SvUPGRADE(sv, SVt_PV)) + return; + SvGROW(sv, len + 1); + if (ptr) + Move(ptr,SvPV(sv),len,char); + SvCUR_set(sv, len); + *SvEND(sv) = '\0'; + SvPOK_only(sv); /* validate pointer */ + SvTDOWN(sv); +} + +void +sv_setpv(sv,ptr) +register SV *sv; +register char *ptr; +{ + register STRLEN len; + + if (SvREADONLY(sv)) + fatal(no_modify); + if (!ptr) + ptr = ""; + len = strlen(ptr); + if (!SvUPGRADE(sv, SVt_PV)) + return; + SvGROW(sv, len + 1); + Move(ptr,SvPV(sv),len+1,char); + SvCUR_set(sv, len); + SvPOK_only(sv); /* validate pointer */ + SvTDOWN(sv); +} + +void +sv_chop(sv,ptr) /* like set but assuming ptr is in sv */ +register SV *sv; +register char *ptr; +{ + register STRLEN delta; + + if (!ptr || !SvPOK(sv)) + return; + if (SvREADONLY(sv)) + fatal(no_modify); + if (SvTYPE(sv) < SVt_PVIV) + sv_upgrade(sv,SVt_PVIV); + + if (!SvOOK(sv)) { + SvIV(sv) = 0; + SvFLAGS(sv) |= SVf_OOK; + } + SvFLAGS(sv) &= ~(SVf_IOK|SVf_NOK); + delta = ptr - SvPV(sv); + SvLEN(sv) -= delta; + SvCUR(sv) -= delta; + SvPV(sv) += delta; + SvIV(sv) += delta; +} + +void +sv_catpvn(sv,ptr,len) +register SV *sv; +register char *ptr; +register STRLEN len; +{ + if (SvREADONLY(sv)) + fatal(no_modify); + if (!(SvPOK(sv))) + (void)sv_2pv(sv); + SvGROW(sv, SvCUR(sv) + len + 1); + Move(ptr,SvPV(sv)+SvCUR(sv),len,char); + SvCUR(sv) += len; + *SvEND(sv) = '\0'; + SvPOK_only(sv); /* validate pointer */ + SvTDOWN(sv); +} + +void +sv_catsv(dstr,sstr) +SV *dstr; +register SV *sstr; +{ + char *s; + if (!sstr) + return; + if (s = SvPVn(sstr)) { + if (SvPOK(sstr)) + sv_catpvn(dstr,s,SvCUR(sstr)); + else + sv_catpv(dstr,s); + } +} + +void +sv_catpv(sv,ptr) +register SV *sv; +register char *ptr; +{ + register STRLEN len; + + if (SvREADONLY(sv)) + fatal(no_modify); + if (!ptr) + return; + if (!(SvPOK(sv))) + (void)sv_2pv(sv); + len = strlen(ptr); + SvGROW(sv, SvCUR(sv) + len + 1); + Move(ptr,SvPV(sv)+SvCUR(sv),len+1,char); + SvCUR(sv) += len; + SvPOK_only(sv); /* validate pointer */ + SvTDOWN(sv); +} + +char * +sv_append_till(sv,from,fromend,delim,keeplist) +register SV *sv; +register char *from; +register char *fromend; +register I32 delim; +char *keeplist; +{ + register char *to; + register STRLEN len; + + if (SvREADONLY(sv)) + fatal(no_modify); + if (!from) + return Nullch; + len = fromend - from; + if (!SvUPGRADE(sv, SVt_PV)) + return 0; + SvGROW(sv, SvCUR(sv) + len + 1); + SvPOK_only(sv); /* validate pointer */ + to = SvPV(sv)+SvCUR(sv); + for (; from < fromend; from++,to++) { + if (*from == '\\' && from+1 < fromend && delim != '\\') { + if (!keeplist) + *to++ = *from++; + else if (from[1] && index(keeplist,from[1])) + *to++ = *from++; + else + from++; + } + else if (*from == delim) + break; + *to = *from; + } + *to = '\0'; + SvCUR_set(sv, to - SvPV(sv)); + return from; +} + +SV * +#ifdef LEAKTEST +newSV(x,len) +I32 x; +#else +newSV(len) +#endif +STRLEN len; +{ + register SV *sv; + + sv = (SV*)new_SV(); + Zero(sv, 1, SV); + SvREFCNT(sv)++; + if (len) { + sv_upgrade(sv, SVt_PV); + SvGROW(sv, len + 1); + } + return sv; +} + +void +sv_magic(sv, obj, how, name, namlen) +register SV *sv; +SV *obj; +char how; +char *name; +STRLEN namlen; +{ + MAGIC* mg; + + if (SvREADONLY(sv)) + fatal(no_modify); + if (!SvUPGRADE(sv, SVt_PVMG)) + return; + Newz(702,mg, 1, MAGIC); + mg->mg_moremagic = SvMAGIC(sv); + SvMAGICAL_on(sv); + SvMAGIC(sv) = mg; + mg->mg_obj = obj; + mg->mg_type = how; + if (name) { + mg->mg_ptr = nsavestr(name, namlen); + mg->mg_len = namlen; + } + switch (how) { + case 0: + mg->mg_virtual = &vtbl_sv; + break; + case 'B': + mg->mg_virtual = &vtbl_bm; + break; + case 'D': + mg->mg_virtual = &vtbl_dbm; + break; + case 'd': + mg->mg_virtual = &vtbl_dbmelem; + break; + case 'E': + mg->mg_virtual = &vtbl_env; + break; + case 'e': + mg->mg_virtual = &vtbl_envelem; + break; + case 'L': + mg->mg_virtual = &vtbl_dbline; + break; + case 'S': + mg->mg_virtual = &vtbl_sig; + break; + case 's': + mg->mg_virtual = &vtbl_sigelem; + break; + case 'U': + mg->mg_virtual = &vtbl_uvar; + break; + case 'v': + mg->mg_virtual = &vtbl_vec; + break; + case 'x': + mg->mg_virtual = &vtbl_substr; + break; + case '*': + mg->mg_virtual = &vtbl_glob; + break; + case '#': + mg->mg_virtual = &vtbl_arylen; + break; + default: + fatal("Don't know how to handle magic of type '%c'", how); + } +} + +void +sv_insert(bigstr,offset,len,little,littlelen) +SV *bigstr; +STRLEN offset; +STRLEN len; +char *little; +STRLEN littlelen; +{ + register char *big; + register char *mid; + register char *midend; + register char *bigend; + register I32 i; + + if (SvREADONLY(bigstr)) + fatal(no_modify); + SvPOK_only(bigstr); + + i = littlelen - len; + if (i > 0) { /* string might grow */ + if (!SvUPGRADE(bigstr, SVt_PV)) + return; + SvGROW(bigstr, SvCUR(bigstr) + i + 1); + big = SvPV(bigstr); + mid = big + offset + len; + midend = bigend = big + SvCUR(bigstr); + bigend += i; + *bigend = '\0'; + while (midend > mid) /* shove everything down */ + *--bigend = *--midend; + Move(little,big+offset,littlelen,char); + SvCUR(bigstr) += i; + SvSETMAGIC(bigstr); + return; + } + else if (i == 0) { + Move(little,SvPV(bigstr)+offset,len,char); + SvSETMAGIC(bigstr); + return; + } + + big = SvPV(bigstr); + mid = big + offset; + midend = mid + len; + bigend = big + SvCUR(bigstr); + + if (midend > bigend) + fatal("panic: sv_insert"); + + if (mid - big > bigend - midend) { /* faster to shorten from end */ + if (littlelen) { + Move(little, mid, littlelen,char); + mid += littlelen; + } + i = bigend - midend; + if (i > 0) { + Move(midend, mid, i,char); + mid += i; + } + *mid = '\0'; + SvCUR_set(bigstr, mid - big); + } + /*SUPPRESS 560*/ + else if (i = mid - big) { /* faster from front */ + midend -= littlelen; + mid = midend; + sv_chop(bigstr,midend-i); + big += i; + while (i--) + *--midend = *--big; + if (littlelen) + Move(little, mid, littlelen,char); + } + else if (littlelen) { + midend -= littlelen; + sv_chop(bigstr,midend); + Move(little,midend,littlelen,char); + } + else { + sv_chop(bigstr,midend); + } + SvSETMAGIC(bigstr); +} + +/* make sv point to what nstr did */ + +void +sv_replace(sv,nsv) +register SV *sv; +register SV *nsv; +{ + U32 refcnt = SvREFCNT(sv); + if (SvREADONLY(sv)) + fatal(no_modify); + if (SvREFCNT(nsv) != 1) + warn("Reference miscount in sv_replace()"); + SvREFCNT(sv) = 0; + sv_clear(sv); + StructCopy(nsv,sv,SV); + SvREFCNT(sv) = refcnt; + Safefree(nsv); +} + +void +sv_clear(sv) +register SV *sv; +{ + assert(sv); + assert(SvREFCNT(sv) == 0); + + switch (SvTYPE(sv)) { + case SVt_PVFM: + goto freemagic; + case SVt_PVBM: + goto freemagic; + case SVt_PVGV: + gp_free(sv); + goto freemagic; + case SVt_PVCV: + op_free(CvSTART(sv)); + goto freemagic; + case SVt_PVHV: + hv_clear(sv, FALSE); + goto freemagic; + case SVt_PVAV: + av_clear(sv); + goto freemagic; + case SVt_PVLV: + goto freemagic; + case SVt_PVMG: + freemagic: + if (SvMAGICAL(sv)) + mg_freeall(sv); + case SVt_PVNV: + case SVt_PVIV: + SvOOK_off(sv); + /* FALL THROUGH */ + case SVt_PV: + if (SvPV(sv)) + Safefree(SvPV(sv)); + break; + case SVt_NV: + break; + case SVt_IV: + break; + case SVt_REF: + sv_free((SV*)SvANY(sv)); + break; + case SVt_NULL: + break; + } + + switch (SvTYPE(sv)) { + case SVt_NULL: + break; + case SVt_REF: + break; + case SVt_IV: + del_XIV(SvANY(sv)); + break; + case SVt_NV: + del_XNV(SvANY(sv)); + break; + case SVt_PV: + del_XPV(SvANY(sv)); + break; + case SVt_PVIV: + del_XPVIV(SvANY(sv)); + break; + case SVt_PVNV: + del_XPVNV(SvANY(sv)); + break; + case SVt_PVMG: + del_XPVMG(SvANY(sv)); + break; + case SVt_PVLV: + del_XPVLV(SvANY(sv)); + break; + case SVt_PVAV: + del_XPVAV(SvANY(sv)); + break; + case SVt_PVHV: + del_XPVHV(SvANY(sv)); + break; + case SVt_PVCV: + del_XPVCV(SvANY(sv)); + break; + case SVt_PVGV: + del_XPVGV(SvANY(sv)); + break; + case SVt_PVBM: + del_XPVBM(SvANY(sv)); + break; + case SVt_PVFM: + del_XPVFM(SvANY(sv)); + break; + } + DEB(SvTYPE(sv) = 0xff;) +} + +SV * +sv_ref(sv) +SV* sv; +{ + SvREFCNT(sv)++; + return sv; +} + +void +sv_free(sv) +SV *sv; +{ + if (!sv) + return; + if (SvREADONLY(sv)) { + if (sv == &sv_undef || sv == &sv_yes || sv == &sv_no) + return; + } + if (SvREFCNT(sv) == 0) { + warn("Attempt to free unreferenced scalar"); + return; + } + if (--SvREFCNT(sv) > 0) + return; + if (SvSTORAGE(sv) == 'O') { + dSP; + BINOP myop; /* fake syntax tree node */ + GV* destructor; + + SvSTORAGE(sv) = 0; /* Curse the object. */ + + ENTER; + SAVESPTR(curcop); + SAVESPTR(op); + curcop = &compiling; + curstash = SvSTASH(sv); + destructor = gv_fetchpv("DESTROY", FALSE); + + if (GvCV(destructor)) { + SV* ref = sv_mortalcopy(&sv_undef); + SvREFCNT(ref) = 1; + sv_upgrade(ref, SVt_REF); + SvANY(ref) = (void*)sv_ref(sv); + + op = (OP*)&myop; + Zero(op, 1, OP); + myop.op_last = (OP*)&myop; + myop.op_flags = OPf_STACKED; + myop.op_next = Nullop; + + EXTEND(SP, 2); + PUSHs((SV*)destructor); + pp_pushmark(); + PUSHs(ref); + PUTBACK; + op = pp_entersubr(); + run(); + stack_sp--; + LEAVE; /* Will eventually free sv as ordinary item. */ + return; + } + LEAVE; + } + sv_clear(sv); + DEB(SvTYPE(sv) = 0xff;) + del_SV(sv); +} + +STRLEN +sv_len(sv) +register SV *sv; +{ + I32 paren; + I32 i; + char *s; + + if (!sv) + return 0; + + if (SvMAGICAL(sv)) + return mg_len(sv, SvMAGIC(sv)); + + if (!(SvPOK(sv))) { + (void)sv_2pv(sv); + if (!SvOK(sv)) + return 0; + } + if (SvPV(sv)) + return SvCUR(sv); + else + return 0; +} + +I32 +sv_eq(str1,str2) +register SV *str1; +register SV *str2; +{ + char *pv1; + U32 cur1; + char *pv2; + U32 cur2; + + if (!str1) { + pv1 = ""; + cur1 = 0; + } + else { + if (SvMAGICAL(str1)) + mg_get(str1); + if (!SvPOK(str1)) { + (void)sv_2pv(str1); + if (!SvPOK(str1)) + str1 = &sv_no; + } + pv1 = SvPV(str1); + cur1 = SvCUR(str1); + } + + if (!str2) + return !cur1; + else { + if (SvMAGICAL(str2)) + mg_get(str2); + if (!SvPOK(str2)) { + (void)sv_2pv(str2); + if (!SvPOK(str2)) + return !cur1; + } + pv2 = SvPV(str2); + cur2 = SvCUR(str2); + } + + if (cur1 != cur2) + return 0; + + return !bcmp(pv1, pv2, cur1); +} + +I32 +sv_cmp(str1,str2) +register SV *str1; +register SV *str2; +{ + I32 retval; + char *pv1; + U32 cur1; + char *pv2; + U32 cur2; + + if (!str1) { + pv1 = ""; + cur1 = 0; + } + else { + if (SvMAGICAL(str1)) + mg_get(str1); + if (!SvPOK(str1)) { + (void)sv_2pv(str1); + if (!SvPOK(str1)) + str1 = &sv_no; + } + pv1 = SvPV(str1); + cur1 = SvCUR(str1); + } + + if (!str2) { + pv2 = ""; + cur2 = 0; + } + else { + if (SvMAGICAL(str2)) + mg_get(str2); + if (!SvPOK(str2)) { + (void)sv_2pv(str2); + if (!SvPOK(str2)) + str2 = &sv_no; + } + pv2 = SvPV(str2); + cur2 = SvCUR(str2); + } + + if (!cur1) + return cur2 ? -1 : 0; + if (!cur2) + return 1; + + if (cur1 < cur2) { + /*SUPPRESS 560*/ + if (retval = memcmp(pv1, pv2, cur1)) + return retval < 0 ? -1 : 1; + else + return -1; + } + /*SUPPRESS 560*/ + else if (retval = memcmp(pv1, pv2, cur2)) + return retval < 0 ? -1 : 1; + else if (cur1 == cur2) + return 0; + else + return 1; +} + +char * +sv_gets(sv,fp,append) +register SV *sv; +register FILE *fp; +I32 append; +{ + register char *bp; /* we're going to steal some values */ + register I32 cnt; /* from the stdio struct and put EVERYTHING */ + register STDCHAR *ptr; /* in the innermost loop into registers */ + register I32 newline = rschar;/* (assuming >= 6 registers) */ + I32 i; + STRLEN bpx; + I32 shortbuffered; + + if (SvREADONLY(sv)) + fatal(no_modify); + if (!SvUPGRADE(sv, SVt_PV)) + return; + if (rspara) { /* have to do this both before and after */ + do { /* to make sure file boundaries work right */ + i = getc(fp); + if (i != '\n') { + ungetc(i,fp); + break; + } + } while (i != EOF); + } +#ifdef STDSTDIO /* Here is some breathtakingly efficient cheating */ + cnt = fp->_cnt; /* get count into register */ + SvPOK_only(sv); /* validate pointer */ + if (SvLEN(sv) - append <= cnt + 1) { /* make sure we have the room */ + if (cnt > 80 && SvLEN(sv) > append) { + shortbuffered = cnt - SvLEN(sv) + append + 1; + cnt -= shortbuffered; + } + else { + shortbuffered = 0; + SvGROW(sv, append+cnt+2);/* (remembering cnt can be -1) */ + } + } + else + shortbuffered = 0; + bp = SvPV(sv) + append; /* move these two too to registers */ + ptr = fp->_ptr; + for (;;) { + screamer: + while (--cnt >= 0) { /* this */ /* eat */ + if ((*bp++ = *ptr++) == newline) /* really */ /* dust */ + goto thats_all_folks; /* screams */ /* sed :-) */ + } + + if (shortbuffered) { /* oh well, must extend */ + cnt = shortbuffered; + shortbuffered = 0; + bpx = bp - SvPV(sv); /* prepare for possible relocation */ + SvCUR_set(sv, bpx); + SvGROW(sv, SvLEN(sv) + append + cnt + 2); + bp = SvPV(sv) + bpx; /* reconstitute our pointer */ + continue; + } + + fp->_cnt = cnt; /* deregisterize cnt and ptr */ + fp->_ptr = ptr; + i = _filbuf(fp); /* get more characters */ + cnt = fp->_cnt; + ptr = fp->_ptr; /* reregisterize cnt and ptr */ + + bpx = bp - SvPV(sv); /* prepare for possible relocation */ + SvCUR_set(sv, bpx); + SvGROW(sv, bpx + cnt + 2); + bp = SvPV(sv) + bpx; /* reconstitute our pointer */ + + if (i == newline) { /* all done for now? */ + *bp++ = i; + goto thats_all_folks; + } + else if (i == EOF) /* all done for ever? */ + goto thats_really_all_folks; + *bp++ = i; /* now go back to screaming loop */ + } + +thats_all_folks: + if (rslen > 1 && (bp - SvPV(sv) < rslen || bcmp(bp - rslen, rs, rslen))) + goto screamer; /* go back to the fray */ +thats_really_all_folks: + if (shortbuffered) + cnt += shortbuffered; + fp->_cnt = cnt; /* put these back or we're in trouble */ + fp->_ptr = ptr; + *bp = '\0'; + SvCUR_set(sv, bp - SvPV(sv)); /* set length */ + +#else /* !STDSTDIO */ /* The big, slow, and stupid way */ + + { + char buf[8192]; + register char * bpe = buf + sizeof(buf) - 3; + +screamer: + bp = buf; + while ((i = getc(fp)) != EOF && (*bp++ = i) != newline && bp < bpe) ; + + if (append) + sv_catpvn(sv, buf, bp - buf); + else + sv_setpvn(sv, buf, bp - buf); + if (i != EOF /* joy */ + && + (i != newline + || + (rslen > 1 + && + (SvCUR(sv) < rslen + || + bcmp(SvPV(sv) + SvCUR(sv) - rslen, rs, rslen) + ) + ) + ) + ) + { + append = -1; + goto screamer; + } + } + +#endif /* STDSTDIO */ + + if (rspara) { + while (i != EOF) { + i = getc(fp); + if (i != '\n') { + ungetc(i,fp); + break; + } + } + } + return SvCUR(sv) - append ? SvPV(sv) : Nullch; +} + +void +sv_inc(sv) +register SV *sv; +{ + register char *d; + + if (!sv) + return; + if (SvREADONLY(sv)) + fatal(no_modify); + if (SvMAGICAL(sv)) + mg_get(sv); + if (SvIOK(sv)) { + ++SvIV(sv); + SvIOK_only(sv); + return; + } + if (SvNOK(sv)) { + SvNV(sv) += 1.0; + SvNOK_only(sv); + return; + } + if (!SvPOK(sv) || !*SvPV(sv)) { + if (!SvUPGRADE(sv, SVt_NV)) + return; + SvNV(sv) = 1.0; + SvNOK_only(sv); + return; + } + d = SvPV(sv); + while (isALPHA(*d)) d++; + while (isDIGIT(*d)) d++; + if (*d) { + sv_setnv(sv,atof(SvPV(sv)) + 1.0); /* punt */ + return; + } + d--; + while (d >= SvPV(sv)) { + if (isDIGIT(*d)) { + if (++*d <= '9') + return; + *(d--) = '0'; + } + else { + ++*d; + if (isALPHA(*d)) + return; + *(d--) -= 'z' - 'a' + 1; + } + } + /* oh,oh, the number grew */ + SvGROW(sv, SvCUR(sv) + 2); + SvCUR(sv)++; + for (d = SvPV(sv) + SvCUR(sv); d > SvPV(sv); d--) + *d = d[-1]; + if (isDIGIT(d[1])) + *d = '1'; + else + *d = d[1]; +} + +void +sv_dec(sv) +register SV *sv; +{ + if (!sv) + return; + if (SvREADONLY(sv)) + fatal(no_modify); + if (SvMAGICAL(sv)) + mg_get(sv); + if (SvIOK(sv)) { + --SvIV(sv); + SvIOK_only(sv); + return; + } + if (SvNOK(sv)) { + SvNV(sv) -= 1.0; + SvNOK_only(sv); + return; + } + if (!SvPOK(sv)) { + if (!SvUPGRADE(sv, SVt_NV)) + return; + SvNV(sv) = -1.0; + SvNOK_only(sv); + return; + } + sv_setnv(sv,atof(SvPV(sv)) - 1.0); +} + +/* Make a string that will exist for the duration of the expression + * evaluation. Actually, it may have to last longer than that, but + * hopefully we won't free it until it has been assigned to a + * permanent location. */ + +SV * +sv_mortalcopy(oldstr) +SV *oldstr; +{ + register SV *sv = NEWSV(78,0); + + sv_setsv(sv,oldstr); + if (++tmps_ix > tmps_max) { + tmps_max = tmps_ix; + if (!(tmps_max & 127)) { + if (tmps_max) + Renew(tmps_stack, tmps_max + 128, SV*); + else + New(702,tmps_stack, 128, SV*); + } + } + tmps_stack[tmps_ix] = sv; + if (SvPOK(sv)) + SvTEMP_on(sv); + return sv; +} + +/* same thing without the copying */ + +SV * +sv_2mortal(sv) +register SV *sv; +{ + if (!sv) + return sv; + if (SvREADONLY(sv)) + fatal(no_modify); + if (++tmps_ix > tmps_max) { + tmps_max = tmps_ix; + if (!(tmps_max & 127)) { + if (tmps_max) + Renew(tmps_stack, tmps_max + 128, SV*); + else + New(704,tmps_stack, 128, SV*); + } + } + tmps_stack[tmps_ix] = sv; + if (SvPOK(sv)) + SvTEMP_on(sv); + return sv; +} + +SV * +newSVpv(s,len) +char *s; +STRLEN len; +{ + register SV *sv = NEWSV(79,0); + + if (!len) + len = strlen(s); + sv_setpvn(sv,s,len); + return sv; +} + +SV * +newSVnv(n) +double n; +{ + register SV *sv = NEWSV(80,0); + + sv_setnv(sv,n); + return sv; +} + +SV * +newSViv(i) +I32 i; +{ + register SV *sv = NEWSV(80,0); + + sv_setiv(sv,i); + return sv; +} + +/* make an exact duplicate of old */ + +SV * +newSVsv(old) +register SV *old; +{ + register SV *new; + + if (!old) + return Nullsv; + if (SvTYPE(old) == 0xff) { + warn("semi-panic: attempt to dup freed string"); + return Nullsv; + } + new = NEWSV(80,0); + if (SvTEMP(old)) { + SvTEMP_off(old); + sv_setsv(new,old); + SvTEMP_on(old); + } + else + sv_setsv(new,old); + return new; +} + +void +sv_reset(s,stash) +register char *s; +HV *stash; +{ + register HE *entry; + register GV *gv; + register SV *sv; + register I32 i; + register PMOP *pm; + register I32 max; + + if (!*s) { /* reset ?? searches */ + for (pm = HvPMROOT(stash); pm; pm = pm->op_pmnext) { + pm->op_pmflags &= ~PMf_USED; + } + return; + } + + /* reset variables */ + + if (!HvARRAY(stash)) + return; + while (*s) { + i = *s; + if (s[1] == '-') { + s += 2; + } + max = *s++; + for ( ; i <= max; i++) { + for (entry = HvARRAY(stash)[i]; + entry; + entry = entry->hent_next) { + gv = (GV*)entry->hent_val; + sv = GvSV(gv); + SvOK_off(sv); + if (SvTYPE(sv) >= SVt_PV) { + SvCUR_set(sv, 0); + SvTDOWN(sv); + if (SvPV(sv) != Nullch) + *SvPV(sv) = '\0'; + } + if (GvAV(gv)) { + av_clear(GvAV(gv)); + } + if (GvHV(gv)) { + hv_clear(GvHV(gv), FALSE); + if (gv == envgv) + environ[0] = Nullch; + } + } + } + } +} + +#ifdef OLD +AV * +sv_2av(sv, st, gvp, lref) +SV *sv; +HV **st; +GV **gvp; +I32 lref; +{ + GV *gv; + + switch (SvTYPE(sv)) { + case SVt_PVAV: + *st = sv->sv_u.sv_stash; + *gvp = Nullgv; + return sv->sv_u.sv_av; + case SVt_PVHV: + case SVt_PVCV: + *gvp = Nullgv; + return Nullav; + default: + if (isGV(sv)) + gv = (GV*)sv; + else + gv = gv_fetchpv(SvPVn(sv), lref); + *gvp = gv; + if (!gv) + return Nullav; + *st = GvESTASH(gv); + if (lref) + return GvAVn(gv); + else + return GvAV(gv); + } +} + +HV * +sv_2hv(sv, st, gvp, lref) +SV *sv; +HV **st; +GV **gvp; +I32 lref; +{ + GV *gv; + + switch (SvTYPE(sv)) { + case SVt_PVHV: + *st = sv->sv_u.sv_stash; + *gvp = Nullgv; + return sv->sv_u.sv_hv; + case SVt_PVAV: + case SVt_PVCV: + *gvp = Nullgv; + return Nullhv; + default: + if (isGV(sv)) + gv = (GV*)sv; + else + gv = gv_fetchpv(SvPVn(sv), lref); + *gvp = gv; + if (!gv) + return Nullhv; + *st = GvESTASH(gv); + if (lref) + return GvHVn(gv); + else + return GvHV(gv); + } +} +#endif; + +CV * +sv_2cv(sv, st, gvp, lref) +SV *sv; +HV **st; +GV **gvp; +I32 lref; +{ + GV *gv; + CV *cv; + + if (!sv) + return Nullcv; + switch (SvTYPE(sv)) { + case SVt_REF: + cv = (CV*)SvANY(sv); + if (SvTYPE(cv) != SVt_PVCV) + fatal("Not a subroutine reference"); + *gvp = Nullgv; + *st = CvSTASH(cv); + return cv; + case SVt_PVCV: + *st = CvSTASH(sv); + *gvp = Nullgv; + return (CV*)sv; + case SVt_PVHV: + case SVt_PVAV: + *gvp = Nullgv; + return Nullcv; + default: + if (isGV(sv)) + gv = (GV*)sv; + else + gv = gv_fetchpv(SvPVn(sv), lref); + *gvp = gv; + if (!gv) + return Nullcv; + *st = GvESTASH(gv); + return GvCV(gv); + } +} + +#ifndef SvTRUE +I32 +SvTRUE(sv) +register SV *sv; +{ + if (SvMAGICAL(sv)) + mg_get(sv); + if (SvPOK(sv)) { + register XPV* Xpv; + if ((Xpv = (XPV*)SvANY(sv)) && + (*Xpv->xpv_pv > '0' || + Xpv->xpv_cur > 1 || + (Xpv->xpv_cur && *Xpv->xpv_pv != '0'))) + return 1; + else + return 0; + } + else { + if (SvIOK(sv)) + return SvIV(sv) != 0; + else { + if (SvNOK(sv)) + return SvNV(sv) != 0.0; + else + return 0; + } + } +} +#endif /* SvTRUE */ + +#ifndef SvNVn +double SvNVn(Sv) +register SV *Sv; +{ + SvTUP(Sv); + if (SvMAGICAL(sv)) + mg_get(sv); + if (SvNOK(Sv)) + return SvNV(Sv); + if (SvIOK(Sv)) + return (double)SvIV(Sv); + return sv_2nv(Sv); +} +#endif /* SvNVn */ + +#ifndef SvPVn +char * +SvPVn(sv) +SV *sv; +{ + SvTUP(sv); + if (SvMAGICAL(sv)) + mg_get(sv); + return SvPOK(sv) ? SvPV(sv) : sv_2pv(sv); +} +#endif + |