summaryrefslogtreecommitdiff
path: root/pp_pack.c
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2013-05-06 19:41:10 +0200
committerNicholas Clark <nick@ccl4.org>2013-05-20 21:19:43 +0200
commita1219b5e0bb6c311848c834f67e70ff7a19c6bf4 (patch)
treeff06cb63988371b951827d37ef57f4c157e3fcfb /pp_pack.c
parente8fda8c499f46bb801215ff1dbea51c1f3007a6c (diff)
downloadperl-a1219b5e0bb6c311848c834f67e70ff7a19c6bf4.tar.gz
Swap byte order in DO_BO_(UN)?PACK based on a variable needs_swap.
Add the macro NEEDS_SWAP to initialise needs_swap based on TYPE_ENDIANNESS(datumtype). This makes the two definitions of DO_BO_UNPACK identical, and the two definitions of DO_BO_PACK identical. This also makes building pp_pack.c on a mixed endian byteorder architecture a compile time error. The commit adds pointers on where to add code to re-instate support for such architectures.
Diffstat (limited to 'pp_pack.c')
-rw-r--r--pp_pack.c23
1 files changed, 19 insertions, 4 deletions
diff --git a/pp_pack.c b/pp_pack.c
index d85eea20d9..281942145c 100644
--- a/pp_pack.c
+++ b/pp_pack.c
@@ -152,6 +152,15 @@ typedef union {
#define PUSH16(utf8, cur, p) PUSH_BYTES(utf8, cur, OFF16(p), SIZE16)
#define PUSH32(utf8, cur, p) PUSH_BYTES(utf8, cur, OFF32(p), SIZE32)
+#if BYTEORDER == 0x4321 || BYTEORDER == 0x87654321 /* big-endian */
+# define NEEDS_SWAP(d) (TYPE_ENDIANNESS(d) == TYPE_IS_LITTLE_ENDIAN)
+#elif BYTEORDER == 0x1234 || BYTEORDER == 0x12345678 /* 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. */
+#endif
+
/* Only to be used inside a loop (see the break) */
#define SHIFT_BYTES(utf8, s, strend, buf, len, datumtype) \
STMT_START { \
@@ -241,14 +250,14 @@ S_mul128(pTHX_ SV *sv, U8 m)
# define DO_BO_UNPACK(var, type) \
STMT_START { \
- if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_LITTLE_ENDIAN) { \
+ if (needs_swap) { \
my_swabn(&var, sizeof(var)); \
} \
} STMT_END
# define DO_BO_PACK(var, type) \
STMT_START { \
- if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_LITTLE_ENDIAN) { \
+ if (needs_swap) { \
my_swabn(&var, sizeof(var)); \
} \
} STMT_END
@@ -257,14 +266,14 @@ S_mul128(pTHX_ SV *sv, U8 m)
# define DO_BO_UNPACK(var, type) \
STMT_START { \
- if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_BIG_ENDIAN) { \
+ if (needs_swap) { \
my_swabn(&var, sizeof(var)); \
} \
} STMT_END
# define DO_BO_PACK(var, type) \
STMT_START { \
- if (TYPE_ENDIANNESS(datumtype) == TYPE_IS_BIG_ENDIAN) { \
+ if (needs_swap) { \
my_swabn(&var, sizeof(var)); \
} \
} STMT_END
@@ -910,6 +919,7 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
packprops_t props;
I32 len;
I32 datumtype = symptr->code;
+ bool needs_swap;
/* do first one only unless in list context
/ is implemented by unpacking the count, then popping it from the
stack, so must check that we're not in the middle of a / */
@@ -947,6 +957,8 @@ S_unpack_rec(pTHX_ tempsym_t* symptr, const char *s, const char *strbeg, const c
}
}
+ needs_swap = NEEDS_SWAP(datumtype);
+
switch(TYPE_NO_ENDIANNESS(datumtype)) {
default:
Perl_croak(aTHX_ "Invalid type '%c' in unpack", (int)TYPE_NO_MODIFIERS(datumtype) );
@@ -2157,6 +2169,7 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
howlen_t howlen = symptr->howlen;
char *start = SvPVX(cat);
char *cur = start + SvCUR(cat);
+ bool needs_swap;
#define NEXTFROM (lengthcode ? lengthcode : items-- > 0 ? *beglist++ : &PL_sv_no)
@@ -2206,6 +2219,8 @@ S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
lengthcode = sv_2mortal(newSViv(count));
}
+ needs_swap = NEEDS_SWAP(datumtype);
+
/* 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 */