This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Swap byte order in DO_BO_(UN)?PACK based on a variable needs_swap.
authorNicholas Clark <nick@ccl4.org>
Mon, 6 May 2013 17:41:10 +0000 (19:41 +0200)
committerNicholas Clark <nick@ccl4.org>
Mon, 20 May 2013 19:19:43 +0000 (21:19 +0200)
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.

pp_pack.c

index d85eea2..2819421 100644 (file)
--- 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 */