/* pp_pack.c
*
- * Copyright (c) 1991-2002, Larry Wall
+ * Copyright (c) 1991-2003, 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.
t--;
while (t > s) {
i = ((*t - '0') << 7) + m;
- *(t--) = '0' + (i % 10);
- m = i / 10;
+ *(t--) = '0' + (char)(i % 10);
+ m = (char)(i / 10);
}
return (sv);
}
case 'U': /* XXXX Is it correct? */
case 'w':
case 'u':
- buf[0] = datumtype;
+ buf[0] = (char)datumtype;
buf[1] = 0;
Perl_croak(aTHX_ "%s not allowed in length fields", buf);
case ',': /* grandfather in commas but with a warning */
if (commas++ == 0 && ckWARN(WARN_UNPACK))
- Perl_warner(aTHX_ WARN_UNPACK,
+ Perl_warner(aTHX_ packWARN(WARN_UNPACK),
"Invalid type in unpack: '%c'", (int)datumtype);
/* FALL THROUGH */
case '%':
#if defined(HAS_LONG_DOUBLE) && defined(USE_LONG_DOUBLE)
long double aldouble;
#endif
- bool do_utf8 = flags & UNPACK_DO_UTF8;
+ bool do_utf8 = (flags & UNPACK_DO_UTF8) != 0;
while ((pat = next_symbol(pat, patend)) < patend) {
datumtype = *pat++ & 0xFF;
Perl_croak(aTHX_ "Invalid type in unpack: '%c'", (int)datumtype);
case ',': /* grandfather in commas but with a warning */
if (commas++ == 0 && ckWARN(WARN_UNPACK))
- Perl_warner(aTHX_ WARN_UNPACK,
+ Perl_warner(aTHX_ packWARN(WARN_UNPACK),
"Invalid type in unpack: '%c'", (int)datumtype);
break;
case '%':
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
while (len-- > 0) {
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
while (len-- > 0) {
if (checksum) {
while (len-- > 0 && s < strend) {
STRLEN alen;
- auint = NATIVE_TO_UNI(utf8n_to_uvchr((U8*)s, strend - s, &alen, 0));
+ auint = NATIVE_TO_UNI(utf8n_to_uvchr((U8*)s, strend - s, &alen, ckWARN(WARN_UTF8) ? 0 : UTF8_ALLOW_ANYUV));
along = alen;
s += along;
if (checksum > bits_in_uv)
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
while (len-- > 0 && s < strend) {
STRLEN alen;
- auint = NATIVE_TO_UNI(utf8n_to_uvchr((U8*)s, strend - s, &alen, 0));
+ auint = NATIVE_TO_UNI(utf8n_to_uvchr((U8*)s, strend - s, &alen, ckWARN(WARN_UTF8) ? 0 : UTF8_ALLOW_ANYUV));
along = alen;
s += along;
sv = NEWSV(37, 0);
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
#if SHORTSIZE != SIZE16
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
#if SHORTSIZE != SIZE16
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
while (len-- > 0) {
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
while (len-- > 0) {
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
while (len-- > 0) {
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
while (len-- > 0) {
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
#if LONGSIZE != SIZE32
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
#if LONGSIZE != SIZE32
}
break;
case 'w':
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
{
sv = Perl_newSVpvf(aTHX_ "%.*"UVf, (int)TYPE_DIGITS(UV), auv);
while (s < strend) {
- sv = mul128(sv, *s & 0x7f);
+ sv = mul128(sv, (U8)(*s & 0x7f));
if (!(*s++ & 0x80)) {
bytes = 0;
break;
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
while (len-- > 0) {
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
while (len-- > 0) {
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
while (len-- > 0) {
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
while (len-- > 0) {
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
while (len-- > 0) {
}
}
else {
+ if (len && (flags & UNPACK_ONLY_ONE))
+ len = 1;
EXTEND(SP, len);
EXTEND_MORTAL(len);
while (len-- > 0) {
d = PL_uudmap[*(U8*)s++] & 077;
else
d = 0;
- hunk[0] = (a << 2) | (b >> 4);
- hunk[1] = (b << 4) | (c >> 2);
- hunk[2] = (c << 6) | d;
+ hunk[0] = (char)((a << 2) | (b >> 4));
+ hunk[1] = (char)((b << 4) | (c >> 2));
+ hunk[2] = (char)((c << 6) | d);
sv_catpvn(sv, hunk, (len > 3) ? 3 : len);
len -= 3;
}
if (*s == '\n')
s++;
- else if (s[1] == '\n') /* possible checksum byte */
- s += 2;
+ else /* possible checksum byte */
+ if (s + 1 < strend && s[1] == '\n')
+ s += 2;
}
XPUSHs(sv_2mortal(sv));
break;
PP(pp_unpack)
{
dSP;
- dPOPPOPssrl;
+ SV *right = (MAXARG > 1) ? POPs : GvSV(PL_defgv);
+ SV *left = POPs;
I32 gimme = GIMME_V;
STRLEN llen;
STRLEN rlen;
Perl_croak(aTHX_ "Invalid type in pack: '%c'", (int)datumtype);
case ',': /* grandfather in commas but with a warning */
if (commas++ == 0 && ckWARN(WARN_PACK))
- Perl_warner(aTHX_ WARN_PACK,
+ Perl_warner(aTHX_ packWARN(WARN_PACK),
"Invalid type in pack: '%c'", (int)datumtype);
break;
case '%':
/* FALL THROUGH */
case 'X':
shrink:
- if (SvCUR(cat) < len)
+ if ((I32)SvCUR(cat) < len)
Perl_croak(aTHX_ "X outside of string");
SvCUR(cat) -= len;
*SvEND(cat) = '\0';
if (datumtype == 'Z')
++len;
}
- if (fromlen >= len) {
+ if ((I32)fromlen >= len) {
sv_catpvn(cat, aptr, len);
if (datumtype == 'Z')
*(SvEND(cat)-1) = '\0';
SvCUR(cat) += (len+7)/8;
SvGROW(cat, SvCUR(cat) + 1);
aptr = SvPVX(cat) + aint;
- if (len > fromlen)
+ if (len > (I32)fromlen)
len = fromlen;
aint = len;
items = 0;
SvCUR(cat) += (len+1)/2;
SvGROW(cat, SvCUR(cat) + 1);
aptr = SvPVX(cat) + aint;
- if (len > fromlen)
+ if (len > (I32)fromlen)
len = fromlen;
aint = len;
items = 0;
aint = SvIV(fromstr);
if ((aint < 0 || aint > 255) &&
ckWARN(WARN_PACK))
- Perl_warner(aTHX_ WARN_PACK,
+ Perl_warner(aTHX_ packWARN(WARN_PACK),
"Character in \"C\" format wrapped");
achar = aint & 255;
sv_catpvn(cat, &achar, sizeof(char));
aint = SvIV(fromstr);
if ((aint < -128 || aint > 127) &&
ckWARN(WARN_PACK))
- Perl_warner(aTHX_ WARN_PACK,
+ Perl_warner(aTHX_ packWARN(WARN_PACK),
"Character in \"c\" format wrapped");
achar = aint & 255;
sv_catpvn(cat, &achar, sizeof(char));
fromstr = NEXTFROM;
auint = UNI_TO_NATIVE(SvUV(fromstr));
SvGROW(cat, SvCUR(cat) + UTF8_MAXLEN + 1);
- SvCUR_set(cat, (char*)uvchr_to_utf8((U8*)SvEND(cat),auint)
- - SvPVX(cat));
+ SvCUR_set(cat,
+ (char*)uvchr_to_utf8_flags((U8*)SvEND(cat),
+ auint,
+ ckWARN(WARN_UTF8) ?
+ 0 : UNICODE_ALLOW_ANY)
+ - SvPVX(cat));
}
*SvEND(cat) = '\0';
break;
case 'f':
while (len-- > 0) {
fromstr = NEXTFROM;
+#ifdef __VOS__
+/* VOS does not automatically map a floating-point overflow
+ during conversion from double to float into infinity, so we
+ do it by hand. This code should either be generalized for
+ any OS that needs it, or removed if and when VOS implements
+ posix-976 (suggestion to support mapping to infinity).
+ Paul.Green@stratus.com 02-04-02. */
+ if (SvNV(fromstr) > FLT_MAX)
+ afloat = _float_constants[0]; /* single prec. inf. */
+ else if (SvNV(fromstr) < -FLT_MAX)
+ afloat = _float_constants[0]; /* single prec. inf. */
+ else afloat = (float)SvNV(fromstr);
+#else
+# if defined(VMS) && !defined(__IEEE_FP)
+/* IEEE fp overflow shenanigans are unavailable on VAX and optional
+ * on Alpha; fake it if we don't have them.
+ */
+ if (SvNV(fromstr) > FLT_MAX)
+ afloat = FLT_MAX;
+ else if (SvNV(fromstr) < -FLT_MAX)
+ afloat = -FLT_MAX;
+ else afloat = (float)SvNV(fromstr);
+# else
afloat = (float)SvNV(fromstr);
+# endif
+#endif
sv_catpvn(cat, (char *)&afloat, sizeof (float));
}
break;
case 'd':
while (len-- > 0) {
fromstr = NEXTFROM;
+#ifdef __VOS__
+/* VOS does not automatically map a floating-point overflow
+ during conversion from long double to double into infinity,
+ so we do it by hand. This code should either be generalized
+ for any OS that needs it, or removed if and when VOS
+ implements posix-976 (suggestion to support mapping to
+ infinity). Paul.Green@stratus.com 02-04-02. */
+ if (SvNV(fromstr) > DBL_MAX)
+ adouble = _double_constants[0]; /* double prec. inf. */
+ else if (SvNV(fromstr) < -DBL_MAX)
+ adouble = _double_constants[0]; /* double prec. inf. */
+ else adouble = (double)SvNV(fromstr);
+#else
+# if defined(VMS) && !defined(__IEEE_FP)
+/* IEEE fp overflow shenanigans are unavailable on VAX and optional
+ * on Alpha; fake it if we don't have them.
+ */
+ if (SvNV(fromstr) > DBL_MAX)
+ adouble = DBL_MAX;
+ else if (SvNV(fromstr) < -DBL_MAX)
+ adouble = -DBL_MAX;
+ else adouble = (double)SvNV(fromstr);
+# else
adouble = (double)SvNV(fromstr);
+# endif
+#endif
sv_catpvn(cat, (char *)&adouble, sizeof (double));
}
break;
case 'w':
while (len-- > 0) {
fromstr = NEXTFROM;
- adouble = Perl_floor(SvNV(fromstr));
+ anv = SvNV(fromstr);
- if (adouble < 0)
+ if (anv < 0)
Perl_croak(aTHX_ "Cannot compress negative numbers");
- if (
-#if UVSIZE > 4 && UVSIZE >= NVSIZE
- adouble <= 0xffffffff
-#else
-# ifdef CXUX_BROKEN_CONSTANT_CONVERT
- adouble <= UV_MAX_cxux
-# else
- adouble <= UV_MAX
-# endif
-#endif
- )
+ /* 0xFFFFFFFFFFFFFFFF may cast to 18446744073709551616.0,
+ which is == UV_MAX_P1. IOK is fine (instead of UV_only), as
+ any negative IVs will have already been got by the croak()
+ above. IOK is untrue for fractions, so we test them
+ against UV_MAX_P1. */
+ if (SvIOK(fromstr) || anv < UV_MAX_P1)
{
- char buf[1 + sizeof(UV)];
+ char buf[(sizeof(UV)*8)/7+1];
char *in = buf + sizeof(buf);
- UV auv = U_V(adouble);
+ UV auv = SvUV(fromstr);
do {
- *--in = (auv & 0x7f) | 0x80;
+ *--in = (char)((auv & 0x7f) | 0x80);
auv >>= 7;
} while (auv);
buf[sizeof(buf) - 1] &= 0x7f; /* clear continue bit */
/* Copy string and check for compliance */
from = SvPV(fromstr, len);
if ((norm = is_an_int(from, len)) == NULL)
- Perl_croak(aTHX_ "can compress only unsigned integer");
+ Perl_croak(aTHX_ "Can only compress unsigned integers");
New('w', result, len, char);
in = result + len;
SvREFCNT_dec(norm); /* free norm */
}
else if (SvNOKp(fromstr)) {
- char buf[sizeof(double) * 2]; /* 8/7 <= 2 */
+ /* 10**NV_MAX_10_EXP is the largest power of 10
+ so 10**(NV_MAX_10_EXP+1) is definately unrepresentable
+ given 10**(NV_MAX_10_EXP+1) == 128 ** x solve for x:
+ x = (NV_MAX_10_EXP+1) * log (10) / log (128)
+ And with that many bytes only Inf can overflow.
+ */
+#ifdef NV_MAX_10_EXP
+ char buf[1 + (int)((NV_MAX_10_EXP + 1) * 0.47456)];
+#else
+ char buf[1 + (int)((308 + 1) * 0.47456)];
+#endif
char *in = buf + sizeof(buf);
+ anv = Perl_floor(anv);
do {
- double next = floor(adouble / 128);
- *--in = (unsigned char)(adouble - (next * 128)) | 0x80;
+ NV next = Perl_floor(anv / 128);
if (in <= buf) /* this cannot happen ;-) */
Perl_croak(aTHX_ "Cannot compress integer");
- adouble = next;
- } while (adouble > 0);
+ *--in = (unsigned char)(anv - (next * 128)) | 0x80;
+ anv = next;
+ } while (anv > 0);
buf[sizeof(buf) - 1] &= 0x7f; /* clear continue bit */
sv_catpvn(cat, in, (buf + sizeof(buf)) - in);
}
/* Copy string and check for compliance */
from = SvPV(fromstr, len);
if ((norm = is_an_int(from, len)) == NULL)
- Perl_croak(aTHX_ "can compress only unsigned integer");
+ Perl_croak(aTHX_ "Can only compress unsigned integers");
New('w', result, len, char);
in = result + len;
|| (SvPADTMP(fromstr)
&& !SvREADONLY(fromstr))))
{
- Perl_warner(aTHX_ WARN_PACK,
+ Perl_warner(aTHX_ packWARN(WARN_PACK),
"Attempt to pack pointer to temporary value");
}
if (SvPOK(fromstr) || SvNIOK(fromstr))
while (fromlen > 0) {
I32 todo;
- if (fromlen > len)
+ if ((I32)fromlen > len)
todo = len;
else
todo = fromlen;