This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
When endian-swapping in unpack, simply copy the bytes in reverse order.
authorNicholas Clark <nick@ccl4.org>
Tue, 7 May 2013 13:15:54 +0000 (15:15 +0200)
committerNicholas Clark <nick@ccl4.org>
Mon, 20 May 2013 19:19:44 +0000 (21:19 +0200)
It is considerably simpler to re-order the bytes before reading them into
the variable of the desired type, than to read into the variable and then
need a specialised "reverse this integer" function for each size of integer.

This should restore support for big endian Crays. It doesn't support
mixed-endian systems. Support for mixed-endian systems can be restored (if
needed) by re-ordering the bytes correctly at the locations which currently
only know how to reverse the bytes.

pp_pack.c

index e0e2db1..8c5c76e 100644 (file)
--- a/pp_pack.c
+++ b/pp_pack.c
@@ -138,7 +138,11 @@ typedef union {
 #  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 uni_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) */
@@ -148,12 +152,12 @@ STMT_START {                                              \
         if (!uni_to_bytes(aTHX_ &s, strend,            \
          (char *) (buf), len, datumtype)) break;       \
     } else {                                           \
-        Copy(s, (char *) (buf), len, char);            \
+        if (needs_swap)                                 \
+            S_reverse_copy(s, (char *) (buf), len);     \
+        else                                            \
+            Copy(s, (char *) (buf), len, char);                \
         s += len;                                      \
     }                                                  \
-    if (needs_swap) {                                   \
-        my_swabn((buf), len);                           \
-    }                                                   \
 } STMT_END
 
 #define SHIFT16(utf8, s, strend, p, datumtype)                          \
@@ -248,6 +252,14 @@ S_mul128(pTHX_ SV *sv, U8 m)
 
 #include "packsizetables.c"
 
+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)
 {
@@ -283,6 +295,11 @@ uni_to_bytes(pTHX_ const char **s, const char *end, const char *buf, int buf_len
     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 (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);
@@ -294,7 +311,10 @@ uni_to_bytes(pTHX_ const char **s, const char *end, const char *buf, int buf_len
            bad |= 2;
            val &= 0xff;
        }
-       *(U8 *)buf++ = (U8)val;
+        if (needs_swap)
+            *(U8 *)--buf = (U8)val;
+        else
+            *(U8 *)buf++ = (U8)val;
     }
     /* We have enough characters for the buffer. Did we have problems ? */
     if (bad) {