diff options
author | Nicholas Clark <nick@ccl4.org> | 2013-05-06 19:41:10 +0200 |
---|---|---|
committer | Nicholas Clark <nick@ccl4.org> | 2013-05-20 21:19:43 +0200 |
commit | a1219b5e0bb6c311848c834f67e70ff7a19c6bf4 (patch) | |
tree | ff06cb63988371b951827d37ef57f4c157e3fcfb /pp_pack.c | |
parent | e8fda8c499f46bb801215ff1dbea51c1f3007a6c (diff) | |
download | perl-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.c | 23 |
1 files changed, 19 insertions, 4 deletions
@@ -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 */ |