# define OFF32(p) ((char *) (p))
#endif
-/* Only to be used inside a loop (see the break) */
-#define SHIFT16(utf8, s, strend, p, datumtype) STMT_START { \
- if (utf8) { \
- if (!uni_to_bytes(aTHX_ &(s), strend, OFF16(p), SIZE16, datumtype)) break; \
- } else { \
- Copy(s, OFF16(p), SIZE16, char); \
- (s) += SIZE16; \
- } \
-} STMT_END
-
-/* Only to be used inside a loop (see the break) */
-#define SHIFT32(utf8, s, strend, p, datumtype) STMT_START { \
- if (utf8) { \
- if (!uni_to_bytes(aTHX_ &(s), strend, OFF32(p), SIZE32, datumtype)) break; \
- } else { \
- Copy(s, OFF32(p), SIZE32, char); \
- (s) += SIZE32; \
- } \
-} STMT_END
-
-#define PUSH16(utf8, cur, p) PUSH_BYTES(utf8, cur, OFF16(p), SIZE16)
-#define PUSH32(utf8, cur, p) PUSH_BYTES(utf8, cur, OFF32(p), SIZE32)
+#define PUSH16(utf8, cur, p, needs_swap) \
+ PUSH_BYTES(utf8, cur, OFF16(p), SIZE16, needs_swap)
+#define PUSH32(utf8, cur, p, needs_swap) \
+ PUSH_BYTES(utf8, cur, OFF32(p), SIZE32, needs_swap)
#if BYTEORDER == 0x4321 || BYTEORDER == 0x87654321 /* big-endian */
# define NEEDS_SWAP(d) (TYPE_ENDIANNESS(d) == TYPE_IS_LITTLE_ENDIAN)
# define NEEDS_SWAP(d) (TYPE_ENDIANNESS(d) == TYPE_IS_BIG_ENDIAN)
#else
# error "Unsupported byteorder"
- /* Need to add code here to re-instate mixed endian support. */
+ /* Need to add code here to re-instate mixed endian support.
+ NEEDS_SWAP would need to hold a flag indicating which action to
+ take, and S_reverse_copy and the code in S_utf8_to_bytes would need
+ logic adding to deal with any mixed-endian transformations needed.
+ */
#endif
/* Only to be used inside a loop (see the break) */
-#define SHIFT_BYTES(utf8, s, strend, buf, len, datumtype) \
+#define SHIFT_BYTES(utf8, s, strend, buf, len, datumtype, needs_swap) \
STMT_START { \
- if (utf8) { \
- if (!uni_to_bytes(aTHX_ &s, strend, \
+ if (UNLIKELY(utf8)) { \
+ if (!S_utf8_to_bytes(aTHX_ &s, strend, \
(char *) (buf), len, datumtype)) break; \
} else { \
- Copy(s, (char *) (buf), len, char); \
+ if (UNLIKELY(needs_swap)) \
+ S_reverse_copy(s, (char *) (buf), len); \
+ else \
+ Copy(s, (char *) (buf), len, char); \
s += len; \
} \
} STMT_END
-#define SHIFT_VAR(utf8, s, strend, var, datumtype) \
- SHIFT_BYTES(utf8, s, strend, &(var), sizeof(var), datumtype)
+#define SHIFT16(utf8, s, strend, p, datumtype, needs_swap) \
+ SHIFT_BYTES(utf8, s, strend, OFF16(p), SIZE16, datumtype, needs_swap)
-#define PUSH_VAR(utf8, aptr, var) \
- PUSH_BYTES(utf8, aptr, &(var), sizeof(var))
+#define SHIFT32(utf8, s, strend, p, datumtype, needs_swap) \
+ SHIFT_BYTES(utf8, s, strend, OFF32(p), SIZE32, datumtype, needs_swap)
+
+#define SHIFT_VAR(utf8, s, strend, var, datumtype, needs_swap) \
+ SHIFT_BYTES(utf8, s, strend, &(var), sizeof(var), datumtype, needs_swap)
+
+#define PUSH_VAR(utf8, aptr, var, needs_swap) \
+ PUSH_BYTES(utf8, aptr, &(var), sizeof(var), needs_swap)
/* Avoid stack overflow due to pathological templates. 100 should be plenty. */
#define MAX_SUB_TEMPLATE_LEVEL 100
/* Explosives and implosives. */
-#if 'I' == 73 && 'J' == 74
-/* On an ASCII/ISO kind of system */
-#define ISUUCHAR(ch) ((ch) >= ' ' && (ch) < 'a')
-#else
-/*
- Some other sort of character set - use memchr() so we don't match
- the null byte.
- */
-#define ISUUCHAR(ch) (memchr(PL_uuemap, (ch), sizeof(PL_uuemap)-1) || (ch) == ' ')
-#endif
+#define ISUUCHAR(ch) (NATIVE_TO_LATIN1(ch) >= NATIVE_TO_LATIN1(' ') \
+ && NATIVE_TO_LATIN1(ch) < NATIVE_TO_LATIN1('a'))
/* type modifiers */
#define TYPE_IS_SHRIEKING 0x100
# define ENDIANNESS_ALLOWED_TYPES "sSiIlLqQjJfFdDpP("
-# define DO_BO_UNPACK(var, type) \
- STMT_START { \
- if (needs_swap) { \
- my_swabn(&var, sizeof(var)); \
- } \
- } STMT_END
-
-# define DO_BO_PACK(var, type) \
- STMT_START { \
- if (needs_swap) { \
- my_swabn(&var, sizeof(var)); \
- } \
- } STMT_END
-
#define PACK_SIZE_CANNOT_CSUM 0x80
#define PACK_SIZE_UNPREDICTABLE 0x40 /* Not a fixed size element */
#define PACK_SIZE_MASK 0x3F
-#include "packsizetables.c"
+#include "packsizetables.inc"
+
+static void
+S_reverse_copy(const char *src, char *dest, STRLEN len)
+{
+ dest += len;
+ while (len--)
+ *--dest = *src++;
+}
STATIC U8
-uni_to_byte(pTHX_ const char **s, const char *end, I32 datumtype)
+utf8_to_byte(pTHX_ const char **s, const char *end, I32 datumtype)
{
STRLEN retlen;
UV val = utf8n_to_uvchr((U8 *) *s, end-*s, &retlen,
}
#define SHIFT_BYTE(utf8, s, strend, datumtype) ((utf8) ? \
- uni_to_byte(aTHX_ &(s), (strend), (datumtype)) : \
+ utf8_to_byte(aTHX_ &(s), (strend), (datumtype)) : \
*(U8 *)(s)++)
STATIC bool
-uni_to_bytes(pTHX_ const char **s, const char *end, const char *buf, int buf_len, I32 datumtype)
+S_utf8_to_bytes(pTHX_ const char **s, const char *end, const char *buf, int buf_len, I32 datumtype)
{
UV val;
STRLEN retlen;
int bad = 0;
const U32 flags = ckWARN(WARN_UTF8) ?
UTF8_CHECK_ONLY : (UTF8_CHECK_ONLY | UTF8_ALLOW_ANY);
+ const bool needs_swap = NEEDS_SWAP(datumtype);
+
+ if (UNLIKELY(needs_swap))
+ buf += buf_len;
+
for (;buf_len > 0; buf_len--) {
if (from >= end) return FALSE;
val = utf8n_to_uvchr((U8 *) from, end-from, &retlen, flags);
bad |= 2;
val &= 0xff;
}
- *(U8 *)buf++ = (U8)val;
+ if (UNLIKELY(needs_swap))
+ *(U8 *)--buf = (U8)val;
+ else
+ *(U8 *)buf++ = (U8)val;
}
/* We have enough characters for the buffer. Did we have problems ? */
if (bad) {
const int flags = ckWARN(WARN_UTF8) ? 0 : UTF8_ALLOW_ANY;
for (ptr = *s; ptr < from; ptr += UTF8SKIP(ptr)) {
if (ptr >= end) break;
- utf8n_to_uvuni((U8 *) ptr, end-ptr, &retlen, flags);
+ utf8n_to_uvchr((U8 *) ptr, end-ptr, &retlen, flags);
}
if (from > end) from = end;
}
return TRUE;
}
-STATIC bool
-next_uni_uu(pTHX_ const char **s, const char *end, I32 *out)
-{
- dVAR;
- STRLEN retlen;
- const UV val = utf8n_to_uvchr((U8 *) *s, end-*s, &retlen, UTF8_CHECK_ONLY);
- if (val >= 0x100 || !ISUUCHAR(val) ||
- retlen == (STRLEN) -1 || retlen == 0) {
- *out = 0;
- return FALSE;
- }
- *out = PL_uudmap[val] & 077;
- *s += retlen;
- return TRUE;
-}
-
STATIC char *
-S_bytes_to_uni(const U8 *start, STRLEN len, char *dest) {
- const U8 * const end = start + len;
-
- PERL_ARGS_ASSERT_BYTES_TO_UNI;
-
- while (start < end) {
- const UV uv = NATIVE_TO_ASCII(*start);
- if (UNI_IS_INVARIANT(uv))
- *dest++ = (char)(U8)UTF_TO_NATIVE(uv);
- else {
- *dest++ = (char)(U8)UTF8_EIGHT_BIT_HI(uv);
- *dest++ = (char)(U8)UTF8_EIGHT_BIT_LO(uv);
- }
- start++;
+S_my_bytes_to_utf8(const U8 *start, STRLEN len, char *dest, const bool needs_swap) {
+ PERL_ARGS_ASSERT_MY_BYTES_TO_UTF8;
+
+ if (UNLIKELY(needs_swap)) {
+ const U8 *p = start + len;
+ while (p-- > start) {
+ append_utf8_from_native_byte(*p, (U8 **) & dest);
+ }
+ } else {
+ const U8 * const end = start + len;
+ while (start < end) {
+ append_utf8_from_native_byte(*start, (U8 **) & dest);
+ start++;
+ }
}
return dest;
}
-#define PUSH_BYTES(utf8, cur, buf, len) \
+#define PUSH_BYTES(utf8, cur, buf, len, needs_swap) \
STMT_START { \
- if (utf8) \
- (cur) = bytes_to_uni((U8 *) buf, len, (cur)); \
+ if (UNLIKELY(utf8)) \
+ (cur) = my_bytes_to_utf8((U8 *) buf, len, (cur), needs_swap); \
else { \
- Copy(buf, cur, len, char); \
+ if (UNLIKELY(needs_swap)) \
+ S_reverse_copy((char *)(buf), cur, len); \
+ else \
+ Copy(buf, cur, len, char); \
(cur) += (len); \
} \
} STMT_END
(start) = sv_exp_grow(cat, gl); \
(cur) = (start) + SvCUR(cat); \
} \
- PUSH_BYTES(utf8, cur, buf, glen); \
+ PUSH_BYTES(utf8, cur, buf, glen, 0); \
} STMT_END
#define PUSH_BYTE(utf8, s, byte) \
STMT_START { \
if (utf8) { \
const U8 au8 = (byte); \
- (s) = bytes_to_uni(&au8, 1, (s)); \
+ (s) = my_bytes_to_utf8(&au8, 1, (s), 0);\
} else *(U8 *)(s)++ = (byte); \
} STMT_END
case e_star:
Perl_croak(aTHX_ "Within []-length '*' not allowed in %s",
_action( symptr ) );
- break;
+
default:
/* e_no_len and e_number */
len = symptr->length;
if (!len) /* Avoid division by 0 */
len = 1;
len = total % len; /* Assumed: the start is aligned. */
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case 'X':
size = -1;
if (total < len)
len = len - star;
else
len = 0;
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case 'x':
case 'A':
case 'Z':
}
Perl_croak(aTHX_ "No group ending character '%c' found in template",
ender);
- return 0;
+ NOT_REACHED; /* NOTREACHED */
}
}
/*
+
+=head1 Pack and Unpack
+
=for apidoc unpackstring
-The engine implementing the unpack() Perl function.
+The engine implementing the C<unpack()> Perl function.
-Using the template pat..patend, this function unpacks the string
-s..strend into a number of mortal SVs, which it pushes onto the perl
-argument (@_) stack (so you will need to issue a C<PUTBACK> before and
-C<SPAGAIN> after the call to this function). It returns the number of
+Using the template C<pat..patend>, this function unpacks the string
+C<s..strend> into a number of mortal SVs, which it pushes onto the perl
+argument (C<@_>) stack (so you will need to issue a C<PUTBACK> before and
+C<SPAGAIN> after the call to this function). It returns the number of
pushed elements.
-The strend and patend pointers should point to the byte following the last
-character of each string.
+The C<strend> and C<patend> pointers should point to the byte following the
+last character of each string.
Although this function returns its values on the perl argument stack, it
doesn't take any parameters from that stack (and thus in particular
-there's no need to do a PUSHMARK before calling it, unlike L</call_pv> for
+there's no need to do a C<PUSHMARK> before calling it, unlike L</call_pv> for
example).
=cut */
STATIC I32
S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const char *strend, const char **new_s )
{
- dVAR; dSP;
+ dSP;
SV *sv = NULL;
const I32 start_sp_offset = SP - PL_stack_base;
howlen_t howlen;
cuv = 0;
cdouble = 0;
continue;
- break;
+
case '(':
{
tempsym_t savsym = *symptr;
break;
}
len = (s - strbeg) % len;
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case 'X':
if (utf8) {
while (len > 0) {
if (ai32 == 0) break;
len -= ai32;
}
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case 'x':
if (utf8) {
while (len>0) {
break;
case '/':
Perl_croak(aTHX_ "'/' must follow a numeric type in unpack");
- break;
+
case 'A':
case 'Z':
case 'a':
if (checksum) {
if (utf8)
while (len >= 8 && s < strend) {
- cuv += PL_bitcount[uni_to_byte(aTHX_ &s, strend, datumtype)];
+ cuv += PL_bitcount[utf8_to_byte(aTHX_ &s, strend, datumtype)];
len -= 8;
}
else
if (len & 7) bits >>= 1;
else if (utf8) {
if (s >= strend) break;
- bits = uni_to_byte(aTHX_ &s, strend, datumtype);
+ bits = utf8_to_byte(aTHX_ &s, strend, datumtype);
} else bits = *(U8 *) s++;
*str++ = bits & 1 ? '1' : '0';
}
if (len & 7) bits <<= 1;
else if (utf8) {
if (s >= strend) break;
- bits = uni_to_byte(aTHX_ &s, strend, datumtype);
+ bits = utf8_to_byte(aTHX_ &s, strend, datumtype);
} else bits = *(U8 *) s++;
*str++ = bits & 0x80 ? '1' : '0';
}
if (len & 1) bits >>= 4;
else if (utf8) {
if (s >= strend) break;
- bits = uni_to_byte(aTHX_ &s, strend, datumtype);
+ bits = utf8_to_byte(aTHX_ &s, strend, datumtype);
} else bits = * (U8 *) s++;
if (!checksum)
*str++ = PL_hexdigit[bits & 15];
if (len & 1) bits <<= 4;
else if (utf8) {
if (s >= strend) break;
- bits = uni_to_byte(aTHX_ &s, strend, datumtype);
+ bits = utf8_to_byte(aTHX_ &s, strend, datumtype);
} else bits = *(U8 *) s++;
if (!checksum)
*str++ = PL_hexdigit[(bits >> 4) & 15];
utf8 = (symptr->flags & FLAG_DO_UTF8) ? 1 : 0;
break;
}
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case 'c':
while (len-- > 0 && s < strend) {
int aint;
STRLEN len;
/* Bug: warns about bad utf8 even if we are short on bytes
and will break out of the loop */
- if (!uni_to_bytes(aTHX_ &ptr, strend, (char *) result, 1,
+ if (!S_utf8_to_bytes(aTHX_ &ptr, strend, (char *) result, 1,
'U'))
break;
len = UTF8SKIP(result);
- if (!uni_to_bytes(aTHX_ &ptr, strend,
+ if (!S_utf8_to_bytes(aTHX_ &ptr, strend,
(char *) &result[1], len-1, 'U')) break;
- auv = utf8n_to_uvuni(result, len, &retlen, UTF8_ALLOW_DEFAULT);
+ auv = NATIVE_TO_UNI(utf8n_to_uvchr(result,
+ len,
+ &retlen,
+ UTF8_ALLOW_DEFAULT));
s = ptr;
} else {
- auv = utf8n_to_uvuni((U8*)s, strend - s, &retlen, UTF8_ALLOW_DEFAULT);
+ auv = NATIVE_TO_UNI(utf8n_to_uvchr((U8*)s,
+ strend - s,
+ &retlen,
+ UTF8_ALLOW_DEFAULT));
if (retlen == (STRLEN) -1 || retlen == 0)
Perl_croak(aTHX_ "Malformed UTF-8 string in unpack");
s += retlen;
#if SHORTSIZE != SIZE16
while (len-- > 0) {
short ashort;
- SHIFT_VAR(utf8, s, strend, ashort, datumtype);
- DO_BO_UNPACK(ashort, s);
+ SHIFT_VAR(utf8, s, strend, ashort, datumtype, needs_swap);
if (!checksum)
mPUSHi(ashort);
else if (checksum > bits_in_uv)
}
break;
#else
- /* Fallthrough! */
+ /* FALLTHROUGH */
#endif
case 's':
while (len-- > 0) {
#if U16SIZE > SIZE16
ai16 = 0;
#endif
- SHIFT16(utf8, s, strend, &ai16, datumtype);
- DO_BO_UNPACK(ai16, 16);
+ SHIFT16(utf8, s, strend, &ai16, datumtype, needs_swap);
#if U16SIZE > SIZE16
if (ai16 > 32767)
ai16 -= 65536;
#if SHORTSIZE != SIZE16
while (len-- > 0) {
unsigned short aushort;
- SHIFT_VAR(utf8, s, strend, aushort, datumtype);
- DO_BO_UNPACK(aushort, s);
+ SHIFT_VAR(utf8, s, strend, aushort, datumtype, needs_swap,
+ needs_swap);
if (!checksum)
mPUSHu(aushort);
else if (checksum > bits_in_uv)
}
break;
#else
- /* Fallthrough! */
+ /* FALLTHROUGH */
#endif
case 'v':
case 'n':
#if U16SIZE > SIZE16
au16 = 0;
#endif
- SHIFT16(utf8, s, strend, &au16, datumtype);
- DO_BO_UNPACK(au16, 16);
+ SHIFT16(utf8, s, strend, &au16, datumtype, needs_swap);
if (datumtype == 'n')
au16 = PerlSock_ntohs(au16);
if (datumtype == 'v')
# if U16SIZE > SIZE16
ai16 = 0;
# endif
- SHIFT16(utf8, s, strend, &ai16, datumtype);
+ SHIFT16(utf8, s, strend, &ai16, datumtype, needs_swap);
+ /* There should never be any byte-swapping here. */
+ assert(!TYPE_ENDIANNESS(datumtype));
if (datumtype == ('n' | TYPE_IS_SHRIEKING))
ai16 = (I16) PerlSock_ntohs((U16) ai16);
if (datumtype == ('v' | TYPE_IS_SHRIEKING))
case 'i' | TYPE_IS_SHRIEKING:
while (len-- > 0) {
int aint;
- SHIFT_VAR(utf8, s, strend, aint, datumtype);
- DO_BO_UNPACK(aint, i);
+ SHIFT_VAR(utf8, s, strend, aint, datumtype, needs_swap);
if (!checksum)
mPUSHi(aint);
else if (checksum > bits_in_uv)
case 'I' | TYPE_IS_SHRIEKING:
while (len-- > 0) {
unsigned int auint;
- SHIFT_VAR(utf8, s, strend, auint, datumtype);
- DO_BO_UNPACK(auint, i);
+ SHIFT_VAR(utf8, s, strend, auint, datumtype, needs_swap);
if (!checksum)
mPUSHu(auint);
else if (checksum > bits_in_uv)
case 'j':
while (len-- > 0) {
IV aiv;
- SHIFT_VAR(utf8, s, strend, aiv, datumtype);
-#if IVSIZE == INTSIZE
- DO_BO_UNPACK(aiv, i);
-#elif IVSIZE == LONGSIZE
- DO_BO_UNPACK(aiv, l);
-#elif defined(HAS_QUAD) && IVSIZE == U64SIZE
- DO_BO_UNPACK(aiv, 64);
-#else
- Perl_croak(aTHX_ "'j' not supported on this platform");
-#endif
+ SHIFT_VAR(utf8, s, strend, aiv, datumtype, needs_swap);
if (!checksum)
mPUSHi(aiv);
else if (checksum > bits_in_uv)
case 'J':
while (len-- > 0) {
UV auv;
- SHIFT_VAR(utf8, s, strend, auv, datumtype);
-#if IVSIZE == INTSIZE
- DO_BO_UNPACK(auv, i);
-#elif IVSIZE == LONGSIZE
- DO_BO_UNPACK(auv, l);
-#elif defined(HAS_QUAD) && IVSIZE == U64SIZE
- DO_BO_UNPACK(auv, 64);
-#else
- Perl_croak(aTHX_ "'J' not supported on this platform");
-#endif
+ SHIFT_VAR(utf8, s, strend, auv, datumtype, needs_swap);
if (!checksum)
mPUSHu(auv);
else if (checksum > bits_in_uv)
#if LONGSIZE != SIZE32
while (len-- > 0) {
long along;
- SHIFT_VAR(utf8, s, strend, along, datumtype);
- DO_BO_UNPACK(along, l);
+ SHIFT_VAR(utf8, s, strend, along, datumtype, needs_swap);
if (!checksum)
mPUSHi(along);
else if (checksum > bits_in_uv)
}
break;
#else
- /* Fallthrough! */
+ /* FALLTHROUGH */
#endif
case 'l':
while (len-- > 0) {
#if U32SIZE > SIZE32
ai32 = 0;
#endif
- SHIFT32(utf8, s, strend, &ai32, datumtype);
- DO_BO_UNPACK(ai32, 32);
+ SHIFT32(utf8, s, strend, &ai32, datumtype, needs_swap);
#if U32SIZE > SIZE32
if (ai32 > 2147483647) ai32 -= 4294967296;
#endif
#if LONGSIZE != SIZE32
while (len-- > 0) {
unsigned long aulong;
- SHIFT_VAR(utf8, s, strend, aulong, datumtype);
- DO_BO_UNPACK(aulong, l);
+ SHIFT_VAR(utf8, s, strend, aulong, datumtype, needs_swap);
if (!checksum)
mPUSHu(aulong);
else if (checksum > bits_in_uv)
}
break;
#else
- /* Fall through! */
+ /* FALLTHROUGH */
#endif
case 'V':
case 'N':
#if U32SIZE > SIZE32
au32 = 0;
#endif
- SHIFT32(utf8, s, strend, &au32, datumtype);
- DO_BO_UNPACK(au32, 32);
+ SHIFT32(utf8, s, strend, &au32, datumtype, needs_swap);
if (datumtype == 'N')
au32 = PerlSock_ntohl(au32);
if (datumtype == 'V')
#if U32SIZE > SIZE32
ai32 = 0;
#endif
- SHIFT32(utf8, s, strend, &ai32, datumtype);
+ SHIFT32(utf8, s, strend, &ai32, datumtype, needs_swap);
+ /* There should never be any byte swapping here. */
+ assert(!TYPE_ENDIANNESS(datumtype));
if (datumtype == ('N' | TYPE_IS_SHRIEKING))
ai32 = (I32)PerlSock_ntohl((U32)ai32);
if (datumtype == ('V' | TYPE_IS_SHRIEKING))
case 'p':
while (len-- > 0) {
const char *aptr;
- SHIFT_VAR(utf8, s, strend, aptr, datumtype);
- DO_BO_UNPACK(aptr, pointer);
+ SHIFT_VAR(utf8, s, strend, aptr, datumtype, needs_swap);
/* newSVpv generates undef if aptr is NULL */
mPUSHs(newSVpv(aptr, 0));
}
U8 ch;
ch = SHIFT_BYTE(utf8, s, strend, datumtype);
auv = (auv << 7) | (ch & 0x7f);
- /* UTF8_IS_XXXXX not right here - using constant 0x80 */
+ /* UTF8_IS_XXXXX not right here because this is a BER, not
+ * UTF-8 format - using constant 0x80 */
if (ch < 0x80) {
bytes = 0;
mPUSHu(auv);
EXTEND(SP, 1);
if (s + sizeof(char*) <= strend) {
char *aptr;
- SHIFT_VAR(utf8, s, strend, aptr, datumtype);
- DO_BO_UNPACK(aptr, pointer);
+ SHIFT_VAR(utf8, s, strend, aptr, datumtype, needs_swap);
/* newSVpvn generates undef if aptr is NULL */
PUSHs(newSVpvn_flags(aptr, len, SVs_TEMP));
}
break;
-#ifdef HAS_QUAD
+#if defined(HAS_QUAD) && IVSIZE >= 8
case 'q':
while (len-- > 0) {
Quad_t aquad;
- SHIFT_VAR(utf8, s, strend, aquad, datumtype);
- DO_BO_UNPACK(aquad, 64);
+ SHIFT_VAR(utf8, s, strend, aquad, datumtype, needs_swap);
if (!checksum)
- mPUSHs(aquad >= IV_MIN && aquad <= IV_MAX ?
- newSViv((IV)aquad) : newSVnv((NV)aquad));
+ mPUSHs(newSViv((IV)aquad));
else if (checksum > bits_in_uv)
cdouble += (NV)aquad;
else
case 'Q':
while (len-- > 0) {
Uquad_t auquad;
- SHIFT_VAR(utf8, s, strend, auquad, datumtype);
- DO_BO_UNPACK(auquad, 64);
+ SHIFT_VAR(utf8, s, strend, auquad, datumtype, needs_swap);
if (!checksum)
- mPUSHs(auquad <= UV_MAX ?
- newSVuv((UV)auquad) : newSVnv((NV)auquad));
+ mPUSHs(newSVuv((UV)auquad));
else if (checksum > bits_in_uv)
cdouble += (NV)auquad;
else
cuv += auquad;
}
break;
-#endif /* HAS_QUAD */
+#endif
/* float and double added gnb@melba.bby.oz.au 22/11/89 */
case 'f':
while (len-- > 0) {
float afloat;
- SHIFT_VAR(utf8, s, strend, afloat, datumtype);
- DO_BO_UNPACK(afloat, float);
+ SHIFT_VAR(utf8, s, strend, afloat, datumtype, needs_swap);
if (!checksum)
mPUSHn(afloat);
else
case 'd':
while (len-- > 0) {
double adouble;
- SHIFT_VAR(utf8, s, strend, adouble, datumtype);
- DO_BO_UNPACK(adouble, double);
+ SHIFT_VAR(utf8, s, strend, adouble, datumtype, needs_swap);
if (!checksum)
mPUSHn(adouble);
else
case 'F':
while (len-- > 0) {
NV_bytes anv;
- SHIFT_BYTES(utf8, s, strend, anv.bytes, sizeof(anv.bytes), datumtype);
- DO_BO_UNPACK(anv.nv, NV);
+ SHIFT_BYTES(utf8, s, strend, anv.bytes, sizeof(anv.bytes),
+ datumtype, needs_swap);
if (!checksum)
mPUSHn(anv.nv);
else
case 'D':
while (len-- > 0) {
ld_bytes aldouble;
- SHIFT_BYTES(utf8, s, strend, aldouble.bytes, sizeof(aldouble.bytes), datumtype);
- DO_BO_UNPACK(aldouble.ld, long double);
+ SHIFT_BYTES(utf8, s, strend, aldouble.bytes,
+ sizeof(aldouble.bytes), datumtype, needs_swap);
+ /* The most common long double format, the x86 80-bit
+ * extended precision, has either 2 or 6 unused bytes,
+ * which may contain garbage, which may contain
+ * unintentional data. While we do zero the bytes of
+ * the long double data in pack(), here in unpack() we
+ * don't, because it's really hard to envision that
+ * reading the long double off aldouble would be
+ * affected by the unused bytes.
+ *
+ * Note that trying to unpack 'long doubles' of 'long
+ * doubles' packed in another system is in the general
+ * case doomed without having more detail. */
if (!checksum)
mPUSHn(aldouble.ld);
else
sv = sv_2mortal(newSV(l));
if (l) SvPOK_on(sv);
}
- if (utf8) {
- while (next_uni_uu(aTHX_ &s, strend, &len)) {
- I32 a, b, c, d;
- char hunk[3];
-
- while (len > 0) {
- next_uni_uu(aTHX_ &s, strend, &a);
- next_uni_uu(aTHX_ &s, strend, &b);
- next_uni_uu(aTHX_ &s, strend, &c);
- next_uni_uu(aTHX_ &s, strend, &d);
- hunk[0] = (char)((a << 2) | (b >> 4));
- hunk[1] = (char)((b << 4) | (c >> 2));
- hunk[2] = (char)((c << 6) | d);
- if (!checksum)
- sv_catpvn(sv, hunk, (len > 3) ? 3 : len);
- len -= 3;
- }
- if (s < strend) {
- if (*s == '\n') {
- s++;
- }
- else {
- /* possible checksum byte */
- const char *skip = s+UTF8SKIP(s);
- if (skip < strend && *skip == '\n')
- s = skip+1;
- }
- }
- }
- } else {
- while (s < strend && *s > ' ' && ISUUCHAR(*s)) {
- I32 a, b, c, d;
- char hunk[3];
-
- len = PL_uudmap[*(U8*)s++] & 077;
- while (len > 0) {
- if (s < strend && ISUUCHAR(*s))
- a = PL_uudmap[*(U8*)s++] & 077;
- else
- a = 0;
- if (s < strend && ISUUCHAR(*s))
- b = PL_uudmap[*(U8*)s++] & 077;
- else
- b = 0;
- if (s < strend && ISUUCHAR(*s))
- c = PL_uudmap[*(U8*)s++] & 077;
- else
- c = 0;
- if (s < strend && ISUUCHAR(*s))
- d = PL_uudmap[*(U8*)s++] & 077;
- else
- d = 0;
- hunk[0] = (char)((a << 2) | (b >> 4));
- hunk[1] = (char)((b << 4) | (c >> 2));
- hunk[2] = (char)((c << 6) | d);
- if (!checksum)
- sv_catpvn(sv, hunk, (len > 3) ? 3 : len);
- len -= 3;
- }
- if (*s == '\n')
- s++;
- else /* possible checksum byte */
- if (s + 1 < strend && s[1] == '\n')
- s += 2;
- }
- }
+
+ /* Note that all legal uuencoded strings are ASCII printables, so
+ * have the same representation under UTF-8 vs not. This means we
+ * can ignore UTF8ness on legal input. For illegal we stop at the
+ * first failure, and don't report where/what that is, so again we
+ * can ignore UTF8ness */
+
+ while (s < strend && *s != ' ' && ISUUCHAR(*s)) {
+ I32 a, b, c, d;
+ char hunk[3];
+
+ len = PL_uudmap[*(U8*)s++] & 077;
+ while (len > 0) {
+ if (s < strend && ISUUCHAR(*s))
+ a = PL_uudmap[*(U8*)s++] & 077;
+ else
+ a = 0;
+ if (s < strend && ISUUCHAR(*s))
+ b = PL_uudmap[*(U8*)s++] & 077;
+ else
+ b = 0;
+ if (s < strend && ISUUCHAR(*s))
+ c = PL_uudmap[*(U8*)s++] & 077;
+ else
+ c = 0;
+ if (s < strend && ISUUCHAR(*s))
+ d = PL_uudmap[*(U8*)s++] & 077;
+ else
+ d = 0;
+ hunk[0] = (char)((a << 2) | (b >> 4));
+ hunk[1] = (char)((b << 4) | (c >> 2));
+ hunk[2] = (char)((c << 6) | d);
+ if (!checksum)
+ sv_catpvn(sv, hunk, (len > 3) ? 3 : len);
+ len -= 3;
+ }
+ if (*s == '\n')
+ s++;
+ else /* possible checksum byte */
+ if (s + 1 < strend && s[1] == '\n')
+ s += 2;
+ }
if (!checksum)
XPUSHs(sv);
break;
- }
+ } /* End of switch */
if (checksum) {
if (strchr("fFdD", TYPE_NO_MODIFIERS(datumtype)) ||
}
while (cdouble < 0.0)
cdouble += anv;
- cdouble = Perl_modf(cdouble / anv, &trouble) * anv;
+ cdouble = Perl_modf(cdouble / anv, &trouble);
+#ifdef LONGDOUBLE_DOUBLEDOUBLE
+ /* Workaround for powerpc doubledouble modfl bug:
+ * close to 1.0L and -1.0L cdouble is 0, and trouble
+ * is cdouble / anv. */
+ if (trouble != Perl_ceil(trouble)) {
+ cdouble = trouble;
+ if (cdouble > 1.0L) cdouble -= 1.0L;
+ if (cdouble < -1.0L) cdouble += 1.0L;
+ }
+#endif
+ cdouble *= anv;
sv = newSVnv(cdouble);
}
else {
PP(pp_unpack)
{
- dVAR;
dSP;
dPOPPOPssrl;
- I32 gimme = GIMME_V;
+ U8 gimme = GIMME_V;
STRLEN llen;
STRLEN rlen;
const char *pat = SvPV_const(left, llen);
}
STATIC U8 *
-doencodes(U8 *h, const char *s, I32 len)
+doencodes(U8 *h, const U8 *s, I32 len)
{
*h++ = PL_uuemap[len];
while (len > 2) {
len -= 3;
}
if (len > 0) {
- const char r = (len > 1 ? s[1] : '\0');
+ const U8 r = (len > 1 ? s[1] : '\0');
*h++ = PL_uuemap[(077 & (s[0] >> 2))];
*h++ = PL_uuemap[(077 & (((s[0] << 4) & 060) | ((r >> 4) & 017)))];
*h++ = PL_uuemap[(077 & ((r << 2) & 074))];
/*
=for apidoc packlist
-The engine implementing pack() Perl function.
+The engine implementing C<pack()> Perl function.
=cut
*/
void
Perl_packlist(pTHX_ SV *cat, const char *pat, const char *patend, SV **beglist, SV **endlist )
{
- dVAR;
tempsym_t sym;
PERL_ARGS_ASSERT_PACKLIST;
from_start = SvPVX_const(sv);
from_end = from_start + SvCUR(sv);
for (from_ptr = from_start; from_ptr < from_end; from_ptr++)
- if (!NATIVE_IS_INVARIANT(*from_ptr)) break;
+ if (!NATIVE_BYTE_IS_INVARIANT(*from_ptr)) break;
if (from_ptr == from_end) {
/* Simple case: no character needs to be changed */
SvUTF8_on(sv);
return SvGROW(sv, len+extend+1);
}
+static SV *
+S_sv_check_infnan(pTHX_ SV *sv, I32 datumtype)
+{
+ SvGETMAGIC(sv);
+ if (UNLIKELY(SvAMAGIC(sv)))
+ sv = sv_2num(sv);
+ if (UNLIKELY(isinfnansv(sv))) {
+ const I32 c = TYPE_NO_MODIFIERS(datumtype);
+ const NV nv = SvNV_nomg(sv);
+ if (c == 'w')
+ Perl_croak(aTHX_ "Cannot compress %"NVgf" in pack", nv);
+ else
+ Perl_croak(aTHX_ "Cannot pack %"NVgf" with '%c'", nv, (int) c);
+ }
+ return sv;
+}
+
+#define SvIV_no_inf(sv,d) \
+ ((sv) = S_sv_check_infnan(aTHX_ sv,d), SvIV_nomg(sv))
+#define SvUV_no_inf(sv,d) \
+ ((sv) = S_sv_check_infnan(aTHX_ sv,d), SvUV_nomg(sv))
+
STATIC
SV **
S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
{
- dVAR;
tempsym_t lookahead;
I32 items = endlist - beglist;
bool found = next_symbol(symptr);
bool utf8 = (symptr->flags & FLAG_PARSE_UTF8) ? 1 : 0;
bool warn_utf8 = ckWARN(WARN_UTF8);
+ char* from;
PERL_ARGS_ASSERT_PACK_REC;
char *cur = start + SvCUR(cat);
bool needs_swap;
-#define NEXTFROM (lengthcode ? lengthcode : items-- > 0 ? *beglist++ : &PL_sv_no)
+#define NEXTFROM (lengthcode ? lengthcode : items > 0 ? (--items, *beglist++) : &PL_sv_no)
+#define PEEKFROM (lengthcode ? lengthcode : items > 0 ? *beglist : &PL_sv_no)
switch (howlen) {
case e_star:
/* Code inside the switch must take care to properly update
cat (CUR length and '\0' termination) if it updated *cur and
doesn't simply leave using break */
- switch(TYPE_NO_ENDIANNESS(datumtype)) {
+ switch (TYPE_NO_ENDIANNESS(datumtype)) {
default:
Perl_croak(aTHX_ "Invalid type '%c' in pack",
(int) TYPE_NO_MODIFIERS(datumtype));
case '%':
Perl_croak(aTHX_ "'%%' may not be used in pack");
- {
- char *from;
+
case '.' | TYPE_IS_SHRIEKING:
case '.':
if (howlen == e_star) from = start;
from = group ? start + group->strbeg : start;
}
fromstr = NEXTFROM;
- len = SvIV(fromstr);
+ len = SvIV_no_inf(fromstr, datumtype);
goto resize;
case '@' | TYPE_IS_SHRIEKING:
case '@':
goto shrink;
}
break;
- }
+
case '(': {
tempsym_t savsym = *symptr;
U32 group_modifiers = TYPE_MODIFIERS(datumtype & ~symptr->flags);
break;
}
len = (cur-start) % len;
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case 'X':
if (utf8) {
if (len < 1) goto no_change;
if (ai32 == 0) goto no_change;
len -= ai32;
}
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case 'x':
goto grow;
case 'A':
if (datumtype == 'Z') len++;
}
GROWING(0, cat, start, cur, len);
- if (!uni_to_bytes(aTHX_ &aptr, end, cur, fromlen,
+ if (!S_utf8_to_bytes(aTHX_ &aptr, end, cur, fromlen,
datumtype | TYPE_IS_PACK))
Perl_croak(aTHX_ "panic: predicted utf8 length not available, "
"for '%c', aptr=%p end=%p cur=%p, fromlen=%"UVuf,
if (howlen == e_star) len = fromlen;
field_len = (len+1)/2;
GROWING(utf8, cat, start, cur, field_len);
- if (!utf8 && len > (I32)fromlen) len = fromlen;
+ if (!utf8_source && len > (I32)fromlen) len = fromlen;
bits = 0;
l = 0;
if (datumtype == 'H')
while (len-- > 0) {
IV aiv;
fromstr = NEXTFROM;
- aiv = SvIV(fromstr);
+ aiv = SvIV_no_inf(fromstr, datumtype);
if ((-128 > aiv || aiv > 127))
Perl_ck_warner(aTHX_ packWARN(WARN_PACK),
"Character in 'c' format wrapped in pack");
while (len-- > 0) {
IV aiv;
fromstr = NEXTFROM;
- aiv = SvIV(fromstr);
+ aiv = SvIV_no_inf(fromstr, datumtype);
if ((0 > aiv || aiv > 0xff))
Perl_ck_warner(aTHX_ packWARN(WARN_PACK),
"Character in 'C' format wrapped in pack");
while (len-- > 0) {
UV auv;
fromstr = NEXTFROM;
- auv = SvUV(fromstr);
+ auv = SvUV_no_inf(fromstr, datumtype);
if (in_bytes) auv = auv % 0x100;
if (utf8) {
W_utf8:
GROWING(0, cat, start, cur, len+UTF8_MAXLEN);
end = start+SvLEN(cat)-UTF8_MAXLEN;
}
- cur = (char *) uvuni_to_utf8_flags((U8 *) cur,
- NATIVE_TO_UNI(auv),
+ cur = (char *) uvchr_to_utf8_flags((U8 *) cur,
+ auv,
warn_utf8 ?
0 : UNICODE_ALLOW_ANY);
} else {
while (len-- > 0) {
UV auv;
fromstr = NEXTFROM;
- auv = SvUV(fromstr);
+ auv = SvUV_no_inf(fromstr, datumtype);
if (utf8) {
U8 buffer[UTF8_MAXLEN], *endb;
- endb = uvuni_to_utf8_flags(buffer, auv,
+ endb = uvchr_to_utf8_flags(buffer, UNI_TO_NATIVE(auv),
warn_utf8 ?
0 : UNICODE_ALLOW_ANY);
if (cur+(endb-buffer)*UTF8_EXPAND >= end) {
len+(endb-buffer)*UTF8_EXPAND);
end = start+SvLEN(cat);
}
- cur = bytes_to_uni(buffer, endb-buffer, cur);
+ cur = my_bytes_to_utf8(buffer, endb-buffer, cur, 0);
} else {
if (cur >= end) {
*cur = '\0';
GROWING(0, cat, start, cur, len+UTF8_MAXLEN);
end = start+SvLEN(cat)-UTF8_MAXLEN;
}
- cur = (char *) uvuni_to_utf8_flags((U8 *) cur, auv,
+ cur = (char *) uvchr_to_utf8_flags((U8 *) cur, UNI_TO_NATIVE(auv),
warn_utf8 ?
0 : UNICODE_ALLOW_ANY);
}
NV anv;
fromstr = NEXTFROM;
anv = SvNV(fromstr);
-# if defined(VMS) && !defined(_IEEE_FP)
+# if (defined(VMS) && !defined(_IEEE_FP)) || defined(DOUBLE_IS_VAX_FLOAT)
/* IEEE fp overflow shenanigans are unavailable on VAX and optional
* on Alpha; fake it if we don't have them.
*/
afloat = -FLT_MAX;
else afloat = (float)anv;
# else
- afloat = (float)anv;
+# if defined(NAN_COMPARE_BROKEN) && defined(Perl_isnan)
+ if(Perl_isnan(anv))
+ afloat = (float)NV_NAN;
+ else
+# endif
+# ifdef NV_INF
+ /* a simple cast to float is undefined if outside
+ * the range of values that can be represented */
+ afloat = (float)(anv > FLT_MAX ? NV_INF :
+ anv < -FLT_MAX ? -NV_INF : anv);
+# endif
# endif
- DO_BO_PACK(afloat, float);
- PUSH_VAR(utf8, cur, afloat);
+ PUSH_VAR(utf8, cur, afloat, needs_swap);
}
break;
case 'd':
NV anv;
fromstr = NEXTFROM;
anv = SvNV(fromstr);
-# if defined(VMS) && !defined(_IEEE_FP)
+# if (defined(VMS) && !defined(_IEEE_FP)) || defined(DOUBLE_IS_VAX_FLOAT)
/* IEEE fp overflow shenanigans are unavailable on VAX and optional
* on Alpha; fake it if we don't have them.
*/
# else
adouble = (double)anv;
# endif
- DO_BO_PACK(adouble, double);
- PUSH_VAR(utf8, cur, adouble);
+ PUSH_VAR(utf8, cur, adouble, needs_swap);
}
break;
case 'F': {
#ifdef __GNUC__
/* to work round a gcc/x86 bug; don't use SvNV */
anv.nv = sv_2nv(fromstr);
+# if defined(LONGDOUBLE_X86_80_BIT) && defined(USE_LONG_DOUBLE) \
+ && LONG_DOUBLESIZE > 10
+ /* GCC sometimes overwrites the padding in the
+ assignment above */
+ Zero(anv.bytes+10, sizeof(anv.bytes) - 10, U8);
+# endif
#else
anv.nv = SvNV(fromstr);
#endif
- DO_BO_PACK(anv, NV);
- PUSH_BYTES(utf8, cur, anv.bytes, sizeof(anv.bytes));
+ PUSH_BYTES(utf8, cur, anv.bytes, sizeof(anv.bytes), needs_swap);
}
break;
}
# ifdef __GNUC__
/* to work round a gcc/x86 bug; don't use SvNV */
aldouble.ld = (long double)sv_2nv(fromstr);
+# if defined(LONGDOUBLE_X86_80_BIT) && LONG_DOUBLESIZE > 10
+ /* GCC sometimes overwrites the padding in the
+ assignment above */
+ Zero(aldouble.bytes+10, sizeof(aldouble.bytes) - 10, U8);
+# endif
# else
aldouble.ld = (long double)SvNV(fromstr);
# endif
- DO_BO_PACK(aldouble, long double);
- PUSH_BYTES(utf8, cur, aldouble.bytes, sizeof(aldouble.bytes));
+ PUSH_BYTES(utf8, cur, aldouble.bytes, sizeof(aldouble.bytes),
+ needs_swap);
}
break;
}
while (len-- > 0) {
I16 ai16;
fromstr = NEXTFROM;
- ai16 = (I16)SvIV(fromstr);
+ ai16 = (I16)SvIV_no_inf(fromstr, datumtype);
ai16 = PerlSock_htons(ai16);
- PUSH16(utf8, cur, &ai16);
+ PUSH16(utf8, cur, &ai16, FALSE);
}
break;
case 'v' | TYPE_IS_SHRIEKING:
while (len-- > 0) {
I16 ai16;
fromstr = NEXTFROM;
- ai16 = (I16)SvIV(fromstr);
+ ai16 = (I16)SvIV_no_inf(fromstr, datumtype);
ai16 = htovs(ai16);
- PUSH16(utf8, cur, &ai16);
+ PUSH16(utf8, cur, &ai16, FALSE);
}
break;
case 'S' | TYPE_IS_SHRIEKING:
while (len-- > 0) {
unsigned short aushort;
fromstr = NEXTFROM;
- aushort = SvUV(fromstr);
- DO_BO_PACK(aushort, s);
- PUSH_VAR(utf8, cur, aushort);
+ aushort = SvUV_no_inf(fromstr, datumtype);
+ PUSH_VAR(utf8, cur, aushort, needs_swap);
}
break;
#else
- /* Fall through! */
+ /* FALLTHROUGH */
#endif
case 'S':
while (len-- > 0) {
U16 au16;
fromstr = NEXTFROM;
- au16 = (U16)SvUV(fromstr);
- DO_BO_PACK(au16, 16);
- PUSH16(utf8, cur, &au16);
+ au16 = (U16)SvUV_no_inf(fromstr, datumtype);
+ PUSH16(utf8, cur, &au16, needs_swap);
}
break;
case 's' | TYPE_IS_SHRIEKING:
while (len-- > 0) {
short ashort;
fromstr = NEXTFROM;
- ashort = SvIV(fromstr);
- DO_BO_PACK(ashort, s);
- PUSH_VAR(utf8, cur, ashort);
+ ashort = SvIV_no_inf(fromstr, datumtype);
+ PUSH_VAR(utf8, cur, ashort, needs_swap);
}
break;
#else
- /* Fall through! */
+ /* FALLTHROUGH */
#endif
case 's':
while (len-- > 0) {
I16 ai16;
fromstr = NEXTFROM;
- ai16 = (I16)SvIV(fromstr);
- DO_BO_PACK(ai16, 16);
- PUSH16(utf8, cur, &ai16);
+ ai16 = (I16)SvIV_no_inf(fromstr, datumtype);
+ PUSH16(utf8, cur, &ai16, needs_swap);
}
break;
case 'I':
while (len-- > 0) {
unsigned int auint;
fromstr = NEXTFROM;
- auint = SvUV(fromstr);
- DO_BO_PACK(auint, i);
- PUSH_VAR(utf8, cur, auint);
+ auint = SvUV_no_inf(fromstr, datumtype);
+ PUSH_VAR(utf8, cur, auint, needs_swap);
}
break;
case 'j':
while (len-- > 0) {
IV aiv;
fromstr = NEXTFROM;
- aiv = SvIV(fromstr);
-#if IVSIZE == INTSIZE
- DO_BO_PACK(aiv, i);
-#elif IVSIZE == LONGSIZE
- DO_BO_PACK(aiv, l);
-#elif defined(HAS_QUAD) && IVSIZE == U64SIZE
- DO_BO_PACK(aiv, 64);
-#else
- Perl_croak(aTHX_ "'j' not supported on this platform");
-#endif
- PUSH_VAR(utf8, cur, aiv);
+ aiv = SvIV_no_inf(fromstr, datumtype);
+ PUSH_VAR(utf8, cur, aiv, needs_swap);
}
break;
case 'J':
while (len-- > 0) {
UV auv;
fromstr = NEXTFROM;
- auv = SvUV(fromstr);
-#if UVSIZE == INTSIZE
- DO_BO_PACK(auv, i);
-#elif UVSIZE == LONGSIZE
- DO_BO_PACK(auv, l);
-#elif defined(HAS_QUAD) && UVSIZE == U64SIZE
- DO_BO_PACK(auv, 64);
-#else
- Perl_croak(aTHX_ "'J' not supported on this platform");
-#endif
- PUSH_VAR(utf8, cur, auv);
+ auv = SvUV_no_inf(fromstr, datumtype);
+ PUSH_VAR(utf8, cur, auv, needs_swap);
}
break;
case 'w':
while (len-- > 0) {
NV anv;
fromstr = NEXTFROM;
- anv = SvNV(fromstr);
+ S_sv_check_infnan(aTHX_ fromstr, datumtype);
+ anv = SvNV_nomg(fromstr);
if (anv < 0) {
*cur = '\0';
if (SvIOK(fromstr) || anv < UV_MAX_P1) {
char buf[(sizeof(UV)*CHAR_BIT)/7+1];
char *in = buf + sizeof(buf);
- UV auv = SvUV(fromstr);
+ UV auv = SvUV_nomg(fromstr);
do {
*--in = (char)((auv & 0x7f) | 0x80);
w_string:
/* Copy string and check for compliance */
- from = SvPV_const(fromstr, len);
+ from = SvPV_nomg_const(fromstr, len);
if ((norm = is_an_int(from, len)) == NULL)
Perl_croak(aTHX_ "Can only compress unsigned integers in pack");
while (len-- > 0) {
int aint;
fromstr = NEXTFROM;
- aint = SvIV(fromstr);
- DO_BO_PACK(aint, i);
- PUSH_VAR(utf8, cur, aint);
+ aint = SvIV_no_inf(fromstr, datumtype);
+ PUSH_VAR(utf8, cur, aint, needs_swap);
}
break;
case 'N' | TYPE_IS_SHRIEKING:
while (len-- > 0) {
U32 au32;
fromstr = NEXTFROM;
- au32 = SvUV(fromstr);
+ au32 = SvUV_no_inf(fromstr, datumtype);
au32 = PerlSock_htonl(au32);
- PUSH32(utf8, cur, &au32);
+ PUSH32(utf8, cur, &au32, FALSE);
}
break;
case 'V' | TYPE_IS_SHRIEKING:
while (len-- > 0) {
U32 au32;
fromstr = NEXTFROM;
- au32 = SvUV(fromstr);
+ au32 = SvUV_no_inf(fromstr, datumtype);
au32 = htovl(au32);
- PUSH32(utf8, cur, &au32);
+ PUSH32(utf8, cur, &au32, FALSE);
}
break;
case 'L' | TYPE_IS_SHRIEKING:
while (len-- > 0) {
unsigned long aulong;
fromstr = NEXTFROM;
- aulong = SvUV(fromstr);
- DO_BO_PACK(aulong, l);
- PUSH_VAR(utf8, cur, aulong);
+ aulong = SvUV_no_inf(fromstr, datumtype);
+ PUSH_VAR(utf8, cur, aulong, needs_swap);
}
break;
#else
while (len-- > 0) {
U32 au32;
fromstr = NEXTFROM;
- au32 = SvUV(fromstr);
- DO_BO_PACK(au32, 32);
- PUSH32(utf8, cur, &au32);
+ au32 = SvUV_no_inf(fromstr, datumtype);
+ PUSH32(utf8, cur, &au32, needs_swap);
}
break;
case 'l' | TYPE_IS_SHRIEKING:
while (len-- > 0) {
long along;
fromstr = NEXTFROM;
- along = SvIV(fromstr);
- DO_BO_PACK(along, l);
- PUSH_VAR(utf8, cur, along);
+ along = SvIV_no_inf(fromstr, datumtype);
+ PUSH_VAR(utf8, cur, along, needs_swap);
}
break;
#else
while (len-- > 0) {
I32 ai32;
fromstr = NEXTFROM;
- ai32 = SvIV(fromstr);
- DO_BO_PACK(ai32, 32);
- PUSH32(utf8, cur, &ai32);
+ ai32 = SvIV_no_inf(fromstr, datumtype);
+ PUSH32(utf8, cur, &ai32, needs_swap);
}
break;
-#ifdef HAS_QUAD
+#if defined(HAS_QUAD) && IVSIZE >= 8
case 'Q':
while (len-- > 0) {
Uquad_t auquad;
fromstr = NEXTFROM;
- auquad = (Uquad_t) SvUV(fromstr);
- DO_BO_PACK(auquad, 64);
- PUSH_VAR(utf8, cur, auquad);
+ auquad = (Uquad_t) SvUV_no_inf(fromstr, datumtype);
+ PUSH_VAR(utf8, cur, auquad, needs_swap);
}
break;
case 'q':
while (len-- > 0) {
Quad_t aquad;
fromstr = NEXTFROM;
- aquad = (Quad_t)SvIV(fromstr);
- DO_BO_PACK(aquad, 64);
- PUSH_VAR(utf8, cur, aquad);
+ aquad = (Quad_t)SvIV_no_inf(fromstr, datumtype);
+ PUSH_VAR(utf8, cur, aquad, needs_swap);
}
break;
-#endif /* HAS_QUAD */
+#endif
case 'P':
len = 1; /* assume SV is correct length */
GROWING(utf8, cat, start, cur, sizeof(char *));
- /* Fall through! */
+ /* FALLTHROUGH */
case 'p':
while (len-- > 0) {
const char *aptr;
* of pack() (and all copies of the result) are
* gone.
*/
- if ((SvTEMP(fromstr) || (SvPADTMP(fromstr) &&
+ if (((SvTEMP(fromstr) && SvREFCNT(fromstr) == 1)
+ || (SvPADTMP(fromstr) &&
!SvREADONLY(fromstr)))) {
Perl_ck_warner(aTHX_ packWARN(WARN_PACK),
"Attempt to pack pointer to temporary value");
else
aptr = SvPV_force_flags_nolen(fromstr, 0);
}
- DO_BO_PACK(aptr, pointer);
- PUSH_VAR(utf8, cur, aptr);
+ PUSH_VAR(utf8, cur, aptr, needs_swap);
}
break;
case 'u': {
todo = fromlen;
if (from_utf8) {
char buffer[64];
- if (!uni_to_bytes(aTHX_ &aptr, aend, buffer, todo,
+ if (!S_utf8_to_bytes(aTHX_ &aptr, aend, buffer, todo,
'u' | TYPE_IS_PACK)) {
*cur = '\0';
SvCUR_set(cat, cur - start);
"aptr=%p, aend=%p, buffer=%p, todo=%ld",
aptr, aend, buffer, (long) todo);
}
- end = doencodes(hunk, buffer, todo);
+ end = doencodes(hunk, (const U8 *)buffer, todo);
} else {
- end = doencodes(hunk, aptr, todo);
+ end = doencodes(hunk, (const U8 *)aptr, todo);
aptr += todo;
}
- PUSH_BYTES(utf8, cur, hunk, end-hunk);
+ PUSH_BYTES(utf8, cur, hunk, end-hunk, 0);
fromlen -= todo;
}
break;
PP(pp_pack)
{
- dVAR; dSP; dMARK; dORIGMARK; dTARGET;
+ dSP; dMARK; dORIGMARK; dTARGET;
SV *cat = TARG;
STRLEN fromlen;
SV *pat_sv = *++MARK;
}
/*
- * Local variables:
- * c-indentation-style: bsd
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
* ex: set ts=8 sts=4 sw=4 et:
*/