summaryrefslogtreecommitdiff
path: root/pp.c
diff options
context:
space:
mode:
authorMalcolm Beattie <mbeattie@sable.ox.ac.uk>1997-10-08 10:19:27 +0000
committerMalcolm Beattie <mbeattie@sable.ox.ac.uk>1997-10-08 10:19:27 +0000
commit93af7a870f71dbbb13443b4087703de0221add17 (patch)
treee767c53d4d4f1783640e5410f94655e45b58b3d0 /pp.c
parentc116a00cf797ec2e6795338ee18b88d975e760c5 (diff)
parent2269e8ecc334a5a77bdb915666547431c0171402 (diff)
downloadperl-93af7a870f71dbbb13443b4087703de0221add17.tar.gz
Merge maint-5.004 branch (5.004_03) with mainline.
MANIFEST is out of sync. p4raw-id: //depot/perl@114
Diffstat (limited to 'pp.c')
-rw-r--r--pp.c94
1 files changed, 69 insertions, 25 deletions
diff --git a/pp.c b/pp.c
index 83ca0e50e0..30a4170fc3 100644
--- a/pp.c
+++ b/pp.c
@@ -16,6 +16,17 @@
#include "perl.h"
/*
+ * The compiler on Concurrent CX/UX systems has a subtle bug which only
+ * seems to show up when compiling pp.c - it generates the wrong double
+ * precision constant value for (double)UV_MAX when used inline in the body
+ * of the code below, so this makes a static variable up front (which the
+ * compiler seems to get correct) and uses it in place of UV_MAX below.
+ */
+#ifdef CXUX_BROKEN_CONSTANT_CONVERT
+static double UV_MAX_cxux = ((double)UV_MAX);
+#endif
+
+/*
* Types used in bitwise operations.
*
* Normally we'd just use IV and UV. However, some hardware and
@@ -1621,37 +1632,56 @@ PP(pp_substr)
STRLEN curlen;
I32 pos;
I32 rem;
+ I32 fail;
I32 lvalue = op->op_flags & OPf_MOD;
char *tmps;
I32 arybase = curcop->cop_arybase;
if (MAXARG > 2)
len = POPi;
- pos = POPi - arybase;
+ pos = POPi;
sv = POPs;
tmps = SvPV(sv, curlen);
- if (pos < 0) {
- pos += curlen + arybase;
- if (pos < 0 && MAXARG < 3)
- pos = 0;
+ if (pos >= arybase) {
+ pos -= arybase;
+ rem = curlen-pos;
+ fail = rem;
+ if (MAXARG > 2) {
+ if (len < 0) {
+ rem += len;
+ if (rem < 0)
+ rem = 0;
+ }
+ else if (rem > len)
+ rem = len;
+ }
}
- if (pos < 0 || pos > curlen) {
- if (dowarn || lvalue)
+ else {
+ pos += curlen;
+ if (MAXARG < 3)
+ rem = curlen;
+ else if (len >= 0) {
+ rem = pos+len;
+ if (rem > (I32)curlen)
+ rem = curlen;
+ }
+ else {
+ rem = curlen+len;
+ if (rem < pos)
+ rem = pos;
+ }
+ if (pos < 0)
+ pos = 0;
+ fail = rem;
+ rem -= pos;
+ }
+ if (fail < 0) {
+ if (dowarn || lvalue)
warn("substr outside of string");
RETPUSHUNDEF;
}
else {
- if (MAXARG < 3)
- len = curlen;
- else if (len < 0) {
- len += curlen - pos;
- if (len < 0)
- len = 0;
- }
tmps += pos;
- rem = curlen - pos; /* rem=how many bytes left*/
- if (rem > len)
- rem = len;
sv_setpvn(TARG, tmps, rem);
if (lvalue) { /* it's an lvalue! */
if (!SvGMAGICAL(sv)) {
@@ -2343,11 +2373,13 @@ PP(pp_splice)
SP++;
if (++MARK < SP) {
- offset = SvIVx(*MARK);
+ offset = i = SvIVx(*MARK);
if (offset < 0)
offset += AvFILL(ary) + 1;
else
offset -= curcop->cop_arybase;
+ if (offset < 0)
+ DIE(no_aelem, i);
if (++MARK < SP) {
length = SvIVx(*MARK++);
if (length < 0)
@@ -2360,12 +2392,6 @@ PP(pp_splice)
offset = 0;
length = AvMAX(ary) + 1;
}
- if (offset < 0) {
- length += offset;
- offset = 0;
- if (length < 0)
- length = 0;
- }
if (offset > AvFILL(ary) + 1)
offset = AvFILL(ary) + 1;
after = AvFILL(ary) + 1 - (offset + length);
@@ -3740,8 +3766,12 @@ PP(pp_pack)
#ifdef BW_BITS
adouble <= BW_MASK
#else
+#ifdef CXUX_BROKEN_CONSTANT_CONVERT
+ adouble <= UV_MAX_cxux
+#else
adouble <= UV_MAX
#endif
+#endif
)
{
char buf[1 + sizeof(UV)];
@@ -3857,7 +3887,21 @@ PP(pp_pack)
case 'p':
while (len-- > 0) {
fromstr = NEXTFROM;
- aptr = SvPV_force(fromstr, na); /* XXX Error if TEMP? */
+ if (fromstr == &sv_undef)
+ aptr = NULL;
+ else {
+ /* XXX better yet, could spirit away the string to
+ * a safe spot and hang on to it until the result
+ * of pack() (and all copies of the result) are
+ * gone.
+ */
+ if (dowarn && (SvTEMP(fromstr) || SvPADTMP(fromstr)))
+ warn("Attempt to pack pointer to temporary value");
+ if (SvPOK(fromstr) || SvNIOK(fromstr))
+ aptr = SvPV(fromstr,na);
+ else
+ aptr = SvPV_force(fromstr,na);
+ }
sv_catpvn(cat, (char*)&aptr, sizeof(char*));
}
break;