X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=doop.c;h=a87f7ef7acdfce0417fdc8200e211f19346b5b1a;hb=3c10ad8e31f7d77e71c048b1746912f41cb540f0;hp=1a2ee51cd33c5f898d6385872ccf1f11b954b99f;hpb=8990e3071044a96302560bbdb5706f3e74cf1bef;p=p5sagit%2Fp5-mst-13.2.git diff --git a/doop.c b/doop.c index 1a2ee51..a87f7ef 100644 --- a/doop.c +++ b/doop.c @@ -1,60 +1,14 @@ -/* $RCSfile: doarg.c,v $$Revision: 4.1 $$Date: 92/08/07 17:19:37 $ +/* doop.c * - * Copyright (c) 1991, 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. * - * $Log: doarg.c,v $ - * Revision 4.1 92/08/07 17:19:37 lwall - * Stage 6 Snapshot - * - * Revision 4.0.1.7 92/06/11 21:07:11 lwall - * patch34: join with null list attempted negative allocation - * patch34: sprintf("%6.4s", "abcdefg") didn't print "abcd " - * - * Revision 4.0.1.6 92/06/08 12:34:30 lwall - * patch20: removed implicit int declarations on funcions - * patch20: pattern modifiers i and o didn't interact right - * patch20: join() now pre-extends target string to avoid excessive copying - * patch20: fixed confusion between a *var's real name and its effective name - * patch20: subroutines didn't localize $`, $&, $', $1 et al correctly - * patch20: usersub routines didn't reclaim temp values soon enough - * patch20: ($<,$>) = ... didn't work on some architectures - * patch20: added Atari ST portability - * - * Revision 4.0.1.5 91/11/11 16:31:58 lwall - * patch19: added little-endian pack/unpack options - * - * Revision 4.0.1.4 91/11/05 16:35:06 lwall - * patch11: /$foo/o optimizer could access deallocated data - * patch11: minimum match length calculation in regexp is now cumulative - * patch11: added some support for 64-bit integers - * patch11: prepared for ctype implementations that don't define isascii() - * patch11: sprintf() now supports any length of s field - * patch11: indirect subroutine calls through magic vars (e.g. &$1) didn't work - * patch11: defined(&$foo) and undef(&$foo) didn't work - * - * Revision 4.0.1.3 91/06/10 01:18:41 lwall - * patch10: pack(hh,1) dumped core - * - * Revision 4.0.1.2 91/06/07 10:42:17 lwall - * patch4: new copyright notice - * patch4: // wouldn't use previous pattern if it started with a null character - * patch4: //o and s///o now optimize themselves fully at runtime - * patch4: added global modifier for pattern matches - * patch4: undef @array disabled "@array" interpolation - * patch4: chop("") was returning "\0" rather than "" - * patch4: vector logical operations &, | and ^ sometimes returned null string - * patch4: syscall couldn't pass numbers with most significant bit set on sparcs - * - * Revision 4.0.1.1 91/04/11 17:40:14 lwall - * patch1: fixed undefined environ problem - * patch1: fixed debugger coredump on subroutines - * - * Revision 4.0 91/03/20 01:06:42 lwall - * 4.0 baseline. - * + */ + +/* + * "'So that was the job I felt I had to do when I started,' thought Sam." */ #include "EXTERN.h" @@ -64,39 +18,36 @@ #include #endif -#ifdef BUGGY_MSC - #pragma function(memcmp) -#endif /* BUGGY_MSC */ - -static void doencodes(); - -#ifdef BUGGY_MSC - #pragma intrinsic(memcmp) -#endif /* BUGGY_MSC */ - I32 do_trans(sv,arg) SV *sv; OP *arg; { register short *tbl; - register char *s; - register I32 matches = 0; + register U8 *s; + register U8 *send; + register U8 *d; register I32 ch; - register char *send; - register char *d; + register I32 matches = 0; register I32 squash = op->op_private & OPpTRANS_SQUASH; STRLEN len; - tbl = (short*) cPVOP->op_pv; - s = SvPV(sv, len); + if (SvREADONLY(sv)) + croak(no_modify); + tbl = (short*)cPVOP->op_pv; + s = (U8*)SvPV(sv, len); + if (!len) + return 0; + if (!SvPOKp(sv)) + s = (U8*)SvPV_force(sv, len); + (void)SvPOK_only(sv); send = s + len; if (!tbl || !s) croak("panic: do_trans"); DEBUG_t( deb("2.TBL\n")); if (!op->op_private) { while (s < send) { - if ((ch = tbl[*s & 0377]) >= 0) { + if ((ch = tbl[*s]) >= 0) { matches++; *s = ch; } @@ -106,7 +57,7 @@ OP *arg; else { d = s; while (s < send) { - if ((ch = tbl[*s & 0377]) >= 0) { + if ((ch = tbl[*s]) >= 0) { *d = ch; if (matches++ && squash) { if (d[-1] == *d) @@ -123,7 +74,7 @@ OP *arg; } matches += send - d; /* account for disappeared chars */ *d = '\0'; - SvCUR_set(sv, d - SvPVX(sv)); + SvCUR_set(sv, d - (U8*)SvPVX(sv)); } SvSETMAGIC(sv); return matches; @@ -198,10 +149,7 @@ register SV **sarg; register char *s; register char *t; register char *f; - bool dolong; -#ifdef QUAD - bool doquad; -#endif /* QUAD */ + char dotype; char ch; register char *send; register SV *arg; @@ -214,7 +162,7 @@ register SV **sarg; sv_setpv(sv,""); len--; /* don't count pattern string */ - t = s = SvPV(*sarg, arglen); + t = s = SvPV(*sarg, arglen); /* XXX Don't know t is writeable */ send = s + arglen; sarg++; for ( ; ; len--) { @@ -230,10 +178,7 @@ register SV **sarg; f = t; *buf = '\0'; xs = buf; -#ifdef QUAD - doquad = -#endif /* QUAD */ - dolong = FALSE; + dotype = '\0'; pre = post = 0; for (t++; t < send; t++) { switch (*t) { @@ -244,18 +189,23 @@ register SV **sarg; len++, sarg--; xlen = strlen(xs); break; + case 'n': case '*': + croak("Use of %c in printf format not supported", *t); + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': case '#': case '-': case '+': case ' ': continue; case 'l': -#ifdef QUAD - if (dolong) { - dolong = FALSE; - doquad = TRUE; - } else +#ifdef HAS_QUAD + if (dotype == 'l') + dotype = 'q'; + else #endif - dolong = TRUE; + dotype = 'l'; + continue; + case 'h': + dotype = 's'; continue; case 'c': ch = *(++t); @@ -272,38 +222,54 @@ register SV **sarg; } break; case 'D': - dolong = TRUE; + dotype = 'l'; /* FALL THROUGH */ case 'd': + case 'i': ch = *(++t); *t = '\0'; -#ifdef QUAD - if (doquad) - (void)sprintf(buf,s,(quad)SvNV(arg)); - else + switch (dotype) { +#ifdef HAS_QUAD + case 'q': + /* perl.h says that if quad is available, IV is quad */ + (void)sprintf(xs,f,(Quad_t)SvIV(arg)); + break; #endif - if (dolong) - (void)sprintf(xs,f,(long)SvNV(arg)); - else - (void)sprintf(xs,f,SvIV(arg)); + case 'l': + (void)sprintf(xs,f,(long)SvIV(arg)); + break; + default: + (void)sprintf(xs,f,(int)SvIV(arg)); + break; + case 's': + (void)sprintf(xs,f,(short)SvIV(arg)); + break; + } xlen = strlen(xs); break; case 'X': case 'O': - dolong = TRUE; + dotype = 'l'; /* FALL THROUGH */ case 'x': case 'o': case 'u': ch = *(++t); *t = '\0'; - value = SvNV(arg); -#ifdef QUAD - if (doquad) - (void)sprintf(buf,s,(unsigned quad)value); - else + switch (dotype) { +#ifdef HAS_QUAD + case 'q': + /* perl.h says that if quad is available, UV is quad */ + (void)sprintf(xs,f,(unsigned Quad_t)SvUV(arg)); + break; #endif - if (dolong) - (void)sprintf(xs,f,U_L(value)); - else - (void)sprintf(xs,f,U_I(value)); + case 'l': + (void)sprintf(xs,f,(unsigned long)SvUV(arg)); + break; + default: + (void)sprintf(xs,f,(unsigned int)SvUV(arg)); + break; + case 's': + (void)sprintf(xs,f,(unsigned short)SvUV(arg)); + break; + } xlen = strlen(xs); break; case 'E': case 'e': case 'f': case 'G': case 'g': @@ -311,6 +277,15 @@ register SV **sarg; *t = '\0'; (void)sprintf(xs,f,SvNV(arg)); xlen = strlen(xs); +#ifdef LC_NUMERIC + /* + * User-defined locales may include arbitrary characters. + * And, unfortunately, some system may alloc the "C" locale + * to be overridden by a malicious user. + */ + if (op->op_type == OP_SPRINTF) + SvTAINTED_on(sv); +#endif /* LC_NUMERIC */ break; case 's': ch = *(++t); @@ -357,6 +332,10 @@ register SV **sarg; } /* end of switch, copy results */ *t = ch; + if (xs == buf && xlen >= sizeof(buf)) { /* Ooops! */ + PerlIO_puts(PerlIO_stderr(),"panic: sprintf overflow - memory corrupted!\n"); + my_exit(1); + } SvGROW(sv, SvCUR(sv) + (f - s) + xlen + 1 + pre + post); sv_catpvn(sv, s, f - s); if (pre) { @@ -386,13 +365,23 @@ SV *sv; register unsigned char *s; register unsigned long lval; I32 mask; + STRLEN targlen; + STRLEN len; if (!targ) return; - s = (unsigned char*)SvPVX(targ); + s = (unsigned char*)SvPV_force(targ, targlen); lval = U_L(SvNV(sv)); offset = LvTARGOFF(sv); size = LvTARGLEN(sv); + + len = (offset + size + 7) / 8; + if (len > targlen) { + s = (unsigned char*)SvGROW(targ, len + 1); + (void)memzero(s + targlen, len - targlen + 1); + SvCUR_set(targ, len); + } + if (size < 8) { mask = (1 << size) - 1; size = offset & 7; @@ -402,6 +391,7 @@ SV *sv; s[offset] |= lval << size; } else { + offset >>= 3; if (size == 8) s[offset] = lval & 255; else if (size == 16) { @@ -422,49 +412,118 @@ do_chop(astr,sv) register SV *astr; register SV *sv; { - register char *tmps; - register I32 i; - AV *ary; - HV *hv; - HE *entry; STRLEN len; - - if (!sv) - return; - if (SvTHINKFIRST(sv)) { - if (SvREADONLY(sv)) - croak("Can't chop readonly value"); - if (SvROK(sv)) - sv_unref(sv); - } + char *s; + if (SvTYPE(sv) == SVt_PVAV) { - I32 max; - SV **array = AvARRAY(sv); - max = AvFILL(sv); - for (i = 0; i <= max; i++) - do_chop(astr,array[i]); - return; + register I32 i; + I32 max; + AV* av = (AV*)sv; + max = AvFILL(av); + for (i = 0; i <= max; i++) { + sv = (SV*)av_fetch(av, i, FALSE); + if (sv && ((sv = *(SV**)sv), sv != &sv_undef)) + do_chop(astr, sv); + } + return; } if (SvTYPE(sv) == SVt_PVHV) { - hv = (HV*)sv; - (void)hv_iterinit(hv); - /*SUPPRESS 560*/ - while (entry = hv_iternext(hv)) - do_chop(astr,hv_iterval(hv,entry)); - return; + HV* hv = (HV*)sv; + HE* entry; + (void)hv_iterinit(hv); + /*SUPPRESS 560*/ + while (entry = hv_iternext(hv)) + do_chop(astr,hv_iterval(hv,entry)); + return; } - tmps = SvPV(sv, len); - if (tmps && len) { - tmps += len - 1; - sv_setpvn(astr,tmps,1); /* remember last char */ - *tmps = '\0'; /* wipe it out */ - SvCUR_set(sv, tmps - SvPVX(sv)); - SvNOK_off(sv); - SvSETMAGIC(sv); + s = SvPV(sv, len); + if (len && !SvPOK(sv)) + s = SvPV_force(sv, len); + if (s && len) { + s += --len; + sv_setpvn(astr, s, 1); + *s = '\0'; + SvCUR_set(sv, len); + SvNIOK_off(sv); } else - sv_setpvn(astr,"",0); -} + sv_setpvn(astr, "", 0); + SvSETMAGIC(sv); +} + +I32 +do_chomp(sv) +register SV *sv; +{ + register I32 count; + STRLEN len; + char *s; + + if (RsSNARF(rs)) + return 0; + count = 0; + if (SvTYPE(sv) == SVt_PVAV) { + register I32 i; + I32 max; + AV* av = (AV*)sv; + max = AvFILL(av); + for (i = 0; i <= max; i++) { + sv = (SV*)av_fetch(av, i, FALSE); + if (sv && ((sv = *(SV**)sv), sv != &sv_undef)) + count += do_chomp(sv); + } + return count; + } + if (SvTYPE(sv) == SVt_PVHV) { + HV* hv = (HV*)sv; + HE* entry; + (void)hv_iterinit(hv); + /*SUPPRESS 560*/ + while (entry = hv_iternext(hv)) + count += do_chomp(hv_iterval(hv,entry)); + return count; + } + s = SvPV(sv, len); + if (len && !SvPOKp(sv)) + s = SvPV_force(sv, len); + if (s && len) { + s += --len; + if (RsPARA(rs)) { + if (*s != '\n') + goto nope; + ++count; + while (len && s[-1] == '\n') { + --len; + --s; + ++count; + } + } + else { + STRLEN rslen; + char *rsptr = SvPV(rs, rslen); + if (rslen == 1) { + if (*s != *rsptr) + goto nope; + ++count; + } + else { + if (len < rslen - 1) + goto nope; + len -= rslen - 1; + s -= rslen - 1; + if (memNE(s, rsptr, rslen)) + goto nope; + count += rslen; + } + } + *s = '\0'; + SvCUR_set(sv, len); + SvNIOK_off(sv); + } + nope: + SvSETMAGIC(sv); + return count; +} void do_vop(optype,sv,left,right) @@ -481,32 +540,35 @@ SV *right; register char *dc; STRLEN leftlen; STRLEN rightlen; - register char *lc = SvPV(left, leftlen); - register char *rc = SvPV(right, rightlen); + register char *lc; + register char *rc; register I32 len; - - if (SvTHINKFIRST(sv)) { - if (SvREADONLY(sv)) - croak("Can't do %s to readonly value", op_name[optype]); - if (SvROK(sv)) - sv_unref(sv); - } + I32 lensave; + char *lsave; + char *rsave; + + if (sv != left || (optype != OP_BIT_AND && !SvOK(sv) && !SvGMAGICAL(sv))) + sv_setpvn(sv, "", 0); /* avoid undef warning on |= and ^= */ + lsave = lc = SvPV(left, leftlen); + rsave = rc = SvPV(right, rightlen); len = leftlen < rightlen ? leftlen : rightlen; - if (SvTYPE(sv) < SVt_PV) - sv_upgrade(sv, SVt_PV); - if (SvCUR(sv) > len) - SvCUR_set(sv, len); - else if (SvCUR(sv) < len) { - SvGROW(sv,len); - (void)memzero(SvPVX(sv) + SvCUR(sv), len - SvCUR(sv)); - SvCUR_set(sv, len); + lensave = len; + if (SvOK(sv) || SvTYPE(sv) > SVt_PVMG) { + dc = SvPV_force(sv, na); + if (SvCUR(sv) < len) { + dc = SvGROW(sv, len + 1); + (void)memzero(dc + SvCUR(sv), len - SvCUR(sv) + 1); + } } - SvPOK_only(sv); - dc = SvPVX(sv); - if (!dc) { - sv_setpvn(sv,"",0); - dc = SvPVX(sv); + else { + I32 needlen = ((optype == OP_BIT_AND) + ? len : (leftlen > rightlen ? leftlen : rightlen)); + Newz(801, dc, needlen + 1, char); + (void)sv_usepvn(sv, dc, needlen); + dc = SvPVX(sv); /* sv_usepvn() calls Renew() */ } + SvCUR_set(sv, len); + (void)SvPOK_only(sv); #ifdef LIBERAL if (len >= sizeof(long)*4 && !((long)dc % sizeof(long)) && @@ -529,7 +591,7 @@ SV *right; *dl++ = *ll++ & *rl++; } break; - case OP_XOR: + case OP_BIT_XOR: while (len--) { *dl++ = *ll++ ^ *rl++; *dl++ = *ll++ ^ *rl++; @@ -553,25 +615,29 @@ SV *right; len = remainder; } #endif - switch (optype) { - case OP_BIT_AND: - while (len--) - *dc++ = *lc++ & *rc++; - break; - case OP_XOR: - while (len--) - *dc++ = *lc++ ^ *rc++; - goto mop_up; - case OP_BIT_OR: - while (len--) - *dc++ = *lc++ | *rc++; - mop_up: - len = SvCUR(sv); - if (rightlen > len) - sv_catpvn(sv, SvPVX(right) + len, rightlen - len); - else if (leftlen > len) - sv_catpvn(sv, SvPVX(left) + len, leftlen - len); - break; + { + switch (optype) { + case OP_BIT_AND: + while (len--) + *dc++ = *lc++ & *rc++; + break; + case OP_BIT_XOR: + while (len--) + *dc++ = *lc++ ^ *rc++; + goto mop_up; + case OP_BIT_OR: + while (len--) + *dc++ = *lc++ | *rc++; + mop_up: + len = lensave; + if (rightlen > len) + sv_catpvn(sv, rsave + len, rightlen - len); + else if (leftlen > len) + sv_catpvn(sv, lsave + len, leftlen - len); + else + *SvEND(sv) = '\0'; + break; + } } } @@ -581,24 +647,48 @@ dARGS { dSP; HV *hv = (HV*)POPs; - register AV *ary = stack; - I32 i; register HE *entry; - char *tmps; SV *tmpstr; - I32 dokeys = (op->op_type == OP_KEYS || op->op_type == OP_RV2HV); - I32 dovalues = (op->op_type == OP_VALUES || op->op_type == OP_RV2HV); + I32 dokeys = (op->op_type == OP_KEYS); + I32 dovalues = (op->op_type == OP_VALUES); + + if (op->op_type == OP_RV2HV || op->op_type == OP_PADHV) + dokeys = dovalues = TRUE; + + if (!hv) { + if (op->op_flags & OPf_MOD) { /* lvalue */ + dTARGET; /* make sure to clear its target here */ + if (SvTYPE(TARG) == SVt_PVLV) + LvTARG(TARG) = Nullsv; + PUSHs(TARG); + } + RETURN; + } + + (void)hv_iterinit(hv); /* always reset iterator regardless */ - if (!hv) + if (op->op_private & OPpLEAVE_VOID) RETURN; + if (GIMME != G_ARRAY) { + I32 i; dTARGET; + if (op->op_flags & OPf_MOD) { /* lvalue */ + if (SvTYPE(TARG) < SVt_PVLV) { + sv_upgrade(TARG, SVt_PVLV); + sv_magic(TARG, Nullsv, 'k', Nullch, 0); + } + LvTYPE(TARG) = 'k'; + LvTARG(TARG) = (SV*)hv; + PUSHs(TARG); + RETURN; + } + if (!SvRMAGICAL(hv) || !mg_find((SV*)hv,'P')) i = HvKEYS(hv); else { i = 0; - (void)hv_iterinit(hv); /*SUPPRESS 560*/ while (entry = hv_iternext(hv)) { i++; @@ -611,26 +701,22 @@ dARGS /* Guess how much room we need. hv_max may be a few too many. Oh well. */ EXTEND(sp, HvMAX(hv) * (dokeys + dovalues)); - (void)hv_iterinit(hv); - PUTBACK; /* hv_iternext and hv_iterval might clobber stack_sp */ while (entry = hv_iternext(hv)) { SPAGAIN; - if (dokeys) { - tmps = hv_iterkey(entry,&i); /* won't clobber stack_sp */ - if (!i) - tmps = ""; - XPUSHs(sv_2mortal(newSVpv(tmps,i))); - } + if (dokeys) + XPUSHs(hv_iterkeysv(entry)); /* won't clobber stack_sp */ if (dovalues) { tmpstr = NEWSV(45,0); PUTBACK; sv_setsv(tmpstr,hv_iterval(hv,entry)); SPAGAIN; DEBUG_H( { - sprintf(buf,"%d%%%d=%d\n",entry->hent_hash, - HvMAX(hv)+1,entry->hent_hash & HvMAX(hv)); - sv_setpv(tmpstr,buf); + sprintf(buf,"%lu%%%d=%lu\n", + (unsigned long)HeHASH(entry), + HvMAX(hv)+1, + (unsigned long)(HeHASH(entry) & HvMAX(hv))); + sv_setpv(tmpstr,buf); } ) XPUSHs(sv_2mortal(tmpstr)); }