X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=doop.c;h=378055fd9cd4bba2bbbcdcd4990dcafe8c66ae67;hb=1304aa9d125296870a384c81cea5102c45d467c8;hp=b8815483b66e6ece6e76b06b883409a03b6add8d;hpb=79072805bf63abe5b5978b5928ab00d360ea3e7f;p=p5sagit%2Fp5-mst-13.2.git diff --git a/doop.c b/doop.c index b881548..378055f 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,38 +18,37 @@ #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; { + dTHR; 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 = SvPVn(sv); - send = s + SvCUR(sv); + 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) - fatal("panic: do_trans"); + 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; } @@ -105,7 +58,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) @@ -122,7 +75,7 @@ OP *arg; } matches += send - d; /* account for disappeared chars */ *d = '\0'; - SvCUR_set(sv, d - SvPV(sv)); + SvCUR_set(sv, d - (U8*)SvPVX(sv)); } SvSETMAGIC(sv); return matches; @@ -137,9 +90,10 @@ register SV **sp; { SV **oldmark = mark; register I32 items = sp - mark; - register char *delim = SvPVn(del); register STRLEN len; - I32 delimlen = SvCUR(del); + STRLEN delimlen; + register char *delim = SvPV(del, delimlen); + STRLEN tmplen; mark++; len = (items > 0 ? (delimlen * (items - 1) ) : 0); @@ -148,12 +102,8 @@ register SV **sp; if (SvLEN(sv) < len + items) { /* current length is way too short */ while (items-- > 0) { if (*mark) { - if (!SvPOK(*mark)) { - sv_2pv(*mark); - if (!SvPOK(*mark)) - *mark = &sv_no; - } - len += SvCUR((*mark)); + SvPV(*mark, tmplen); + len += tmplen; } mark++; } @@ -164,8 +114,17 @@ register SV **sp; ++mark; } - if (items-- > 0) - sv_setsv(sv, *mark++); + if (items-- > 0) { + char *s; + + if (*mark) { + s = SvPV(*mark, tmplen); + sv_setpvn(sv, s, tmplen); + } + else + sv_setpv(sv, ""); + mark++; + } else sv_setpv(sv,""); len = delimlen; @@ -184,191 +143,18 @@ register SV **sp; void do_sprintf(sv,len,sarg) -register SV *sv; -register I32 len; -register SV **sarg; +SV *sv; +I32 len; +SV **sarg; { - register char *s; - register char *t; - register char *f; - bool dolong; -#ifdef QUAD - bool doquad; -#endif /* QUAD */ - char ch; - register char *send; - register SV *arg; - char *xs; - I32 xlen; - I32 pre; - I32 post; - double value; - - sv_setpv(sv,""); - len--; /* don't count pattern string */ - t = s = SvPVn(*sarg); - send = s + SvCUR(*sarg); - sarg++; - for ( ; ; len--) { - - /*SUPPRESS 560*/ - if (len <= 0 || !(arg = *sarg++)) - arg = &sv_no; - - /*SUPPRESS 530*/ - for ( ; t < send && *t != '%'; t++) ; - if (t >= send) - break; /* end of run_format string, ignore extra args */ - f = t; - *buf = '\0'; - xs = buf; -#ifdef QUAD - doquad = -#endif /* QUAD */ - dolong = FALSE; - pre = post = 0; - for (t++; t < send; t++) { - switch (*t) { - default: - ch = *(++t); - *t = '\0'; - (void)sprintf(xs,f); - len++, sarg--; - xlen = strlen(xs); - break; - 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 'lXXX': -#ifdef QUAD - if (dolong) { - dolong = FALSE; - doquad = TRUE; - } else -#endif - dolong = TRUE; - continue; - case 'c': - ch = *(++t); - *t = '\0'; - xlen = SvIVn(arg); - if (strEQ(f,"%c")) { /* some printfs fail on null chars */ - *xs = xlen; - xs[1] = '\0'; - xlen = 1; - } - else { - (void)sprintf(xs,f,xlen); - xlen = strlen(xs); - } - break; - case 'D': - dolong = TRUE; - /* FALL THROUGH */ - case 'd': - ch = *(++t); - *t = '\0'; -#ifdef QUAD - if (doquad) - (void)sprintf(buf,s,(quad)SvNVn(arg)); - else -#endif - if (dolong) - (void)sprintf(xs,f,(long)SvNVn(arg)); - else - (void)sprintf(xs,f,SvIVn(arg)); - xlen = strlen(xs); - break; - case 'X': case 'O': - dolong = TRUE; - /* FALL THROUGH */ - case 'x': case 'o': case 'u': - ch = *(++t); - *t = '\0'; - value = SvNVn(arg); -#ifdef QUAD - if (doquad) - (void)sprintf(buf,s,(unsigned quad)value); - else -#endif - if (dolong) - (void)sprintf(xs,f,U_L(value)); - else - (void)sprintf(xs,f,U_I(value)); - xlen = strlen(xs); - break; - case 'E': case 'e': case 'f': case 'G': case 'g': - ch = *(++t); - *t = '\0'; - (void)sprintf(xs,f,SvNVn(arg)); - xlen = strlen(xs); - break; - case 's': - ch = *(++t); - *t = '\0'; - xs = SvPVn(arg); - if (SvPOK(arg)) - xlen = SvCUR(arg); - else - xlen = strlen(xs); - if (strEQ(f,"%s")) { /* some printfs fail on >128 chars */ - break; /* so handle simple cases */ - } - else if (f[1] == '-') { - char *mp = index(f, '.'); - I32 min = atoi(f+2); - - if (mp) { - I32 max = atoi(mp+1); - - if (xlen > max) - xlen = max; - } - if (xlen < min) - post = min - xlen; - break; - } - else if (isDIGIT(f[1])) { - char *mp = index(f, '.'); - I32 min = atoi(f+1); - - if (mp) { - I32 max = atoi(mp+1); - - if (xlen > max) - xlen = max; - } - if (xlen < min) - pre = min - xlen; - break; - } - strcpy(tokenbuf+64,f); /* sprintf($s,...$s...) */ - *t = ch; - (void)sprintf(buf,tokenbuf+64,xs); - xs = buf; - xlen = strlen(xs); - break; - } - /* end of switch, copy results */ - *t = ch; - SvGROW(sv, SvCUR(sv) + (f - s) + xlen + 1 + pre + post); - sv_catpvn(sv, s, f - s); - if (pre) { - repeatcpy(SvPV(sv) + SvCUR(sv), " ", 1, pre); - SvCUR(sv) += pre; - } - sv_catpvn(sv, xs, xlen); - if (post) { - repeatcpy(SvPV(sv) + SvCUR(sv), " ", 1, post); - SvCUR(sv) += post; - } - s = t; - break; /* break from for loop */ - } - } - sv_catpvn(sv, s, t - s); + STRLEN patlen; + char *pat = SvPV(*sarg, patlen); + bool do_taint = FALSE; + + sv_vsetpvfn(sv, pat, patlen, Null(va_list*), sarg + 1, len - 1, &do_taint); SvSETMAGIC(sv); + if (do_taint) + SvTAINTED_on(sv); } void @@ -378,12 +164,26 @@ SV *sv; SV *targ = LvTARG(sv); register I32 offset; register I32 size; - register unsigned char *s = (unsigned char*)SvPV(targ); - register unsigned long lval = U_L(SvNVn(sv)); + register unsigned char *s; + register unsigned long lval; I32 mask; + STRLEN targlen; + STRLEN len; + if (!targ) + return; + 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; @@ -393,6 +193,7 @@ SV *sv; s[offset] |= lval << size; } else { + offset >>= 3; if (size == 8) s[offset] = lval & 255; else if (size == 16) { @@ -413,42 +214,118 @@ do_chop(astr,sv) register SV *astr; register SV *sv; { - register char *tmps; - register I32 i; - AV *ary; - HV *hash; - HE *entry; - - if (!sv) - return; + STRLEN len; + 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) { - hash = (HV*)sv; - (void)hv_iterinit(hash); - /*SUPPRESS 560*/ - while (entry = hv_iternext(hash)) - do_chop(astr,hv_iterval(hash,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 = SvPVn(sv); - if (tmps && SvCUR(sv)) { - tmps += SvCUR(sv) - 1; - sv_setpvn(astr,tmps,1); /* remember last char */ - *tmps = '\0'; /* wipe it out */ - SvCUR_set(sv, tmps - SvPV(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) @@ -463,28 +340,37 @@ SV *right; register long *rl; #endif register char *dc; - register char *lc = SvPVn(left); - register char *rc = SvPVn(right); + STRLEN leftlen; + STRLEN rightlen; + register char *lc; + register char *rc; register I32 len; + I32 lensave; + char *lsave; + char *rsave; - len = SvCUR(left); - if (len > SvCUR(right)) - len = SvCUR(right); - 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(SvPV(sv) + SvCUR(sv), len - SvCUR(sv)); - SvCUR_set(sv, len); + 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; + 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 = SvPV(sv); - if (!dc) { - sv_setpvn(sv,"",0); - dc = SvPV(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)) && @@ -507,7 +393,7 @@ SV *right; *dl++ = *ll++ & *rl++; } break; - case OP_XOR: + case OP_BIT_XOR: while (len--) { *dl++ = *ll++ ^ *rl++; *dl++ = *ll++ ^ *rl++; @@ -531,24 +417,115 @@ 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 (SvCUR(right) > len) - sv_catpvn(sv,SvPV(right)+len,SvCUR(right) - len); - else if (SvCUR(left) > len) - sv_catpvn(sv,SvPV(left)+len,SvCUR(left) - 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; + } + } +} + +OP * +do_kv(ARGS) +dARGS +{ + dSP; + HV *hv = (HV*)POPs; + register HE *entry; + SV *tmpstr; + I32 gimme = GIMME_V; + I32 dokeys = (op->op_type == OP_KEYS); + I32 dovalues = (op->op_type == OP_VALUES); + I32 realhv = (SvTYPE(hv) == SVt_PVHV); + + 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; + } + + if (realhv) + (void)hv_iterinit(hv); /* always reset iterator regardless */ + else + (void)avhv_iterinit((AV*)hv); + + if (gimme == G_VOID) + RETURN; + + if (gimme == G_SCALAR) { + 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; + /*SUPPRESS 560*/ + while (entry = realhv ? hv_iternext(hv) : avhv_iternext((AV*)hv)) { + i++; + } + } + PUSHi( i ); + RETURN; + } + + /* Guess how much room we need. hv_max may be a few too many. Oh well. */ + EXTEND(sp, HvMAX(hv) * (dokeys + dovalues)); + + PUTBACK; /* hv_iternext and hv_iterval might clobber stack_sp */ + while (entry = realhv ? hv_iternext(hv) : avhv_iternext((AV*)hv)) { + SPAGAIN; + if (dokeys) + XPUSHs(hv_iterkeysv(entry)); /* won't clobber stack_sp */ + if (dovalues) { + tmpstr = sv_newmortal(); + PUTBACK; + sv_setsv(tmpstr,realhv ? + hv_iterval(hv,entry) : avhv_iterval((AV*)hv,entry)); + DEBUG_H(sv_setpvf(tmpstr, "%lu%%%d=%lu", + (unsigned long)HeHASH(entry), + HvMAX(hv)+1, + (unsigned long)(HeHASH(entry) & HvMAX(hv)))); + SPAGAIN; + XPUSHs(tmpstr); + } + PUTBACK; } + return NORMAL; }