summaryrefslogtreecommitdiff
path: root/pp_pack.c
diff options
context:
space:
mode:
authorMarcus Holland-Moritz <mhx-perl@gmx.net>2004-05-03 22:14:41 +0200
committerMarcus Holland-Moritz <mhx-perl@gmx.net>2004-05-04 14:46:05 +0000
commit66c611c54494622936416a3e5713bc7d44ef96ba (patch)
tree4525abf5dad52150d4f4db8ac10ee4cf5c7b34d9 /pp_pack.c
parent2cc7004b6c4549e1be46c2a567acf33609c2a687 (diff)
downloadperl-66c611c54494622936416a3e5713bc7d44ef96ba.tar.gz
Add byte-order group modifiers to (un)pack templates.
Follow-up on: #22734, #22745, #22753, #22754. Subject: Group modifiers in (un)pack templates Message-Id: <20040503201441.1b058e0d@r2d2> p4raw-id: //depot/perl@22780
Diffstat (limited to 'pp_pack.c')
-rw-r--r--pp_pack.c60
1 files changed, 45 insertions, 15 deletions
diff --git a/pp_pack.c b/pp_pack.c
index 04645369de..d7ebf3d074 100644
--- a/pp_pack.c
+++ b/pp_pack.c
@@ -72,7 +72,7 @@
/* Avoid stack overflow due to pathological templates. 100 should be plenty. */
#define MAX_SUB_TEMPLATE_LEVEL 100
-/* flags */
+/* flags (note that type modifiers can also be used as flags!) */
#define FLAG_UNPACK_ONLY_ONE 0x10
#define FLAG_UNPACK_DO_UTF8 0x08
#define FLAG_SLASH 0x04
@@ -119,16 +119,21 @@ S_mul128(pTHX_ SV *sv, U8 m)
#define ISUUCHAR(ch) (memchr(PL_uuemap, (ch), sizeof(PL_uuemap)-1) || (ch) == ' ')
#endif
+/* type modifiers */
#define TYPE_IS_SHRIEKING 0x100
#define TYPE_IS_BIG_ENDIAN 0x200
#define TYPE_IS_LITTLE_ENDIAN 0x400
#define TYPE_ENDIANNESS_MASK (TYPE_IS_BIG_ENDIAN|TYPE_IS_LITTLE_ENDIAN)
+#define TYPE_ENDIANNESS(t) ((t) & TYPE_ENDIANNESS_MASK)
#define TYPE_NO_ENDIANNESS(t) ((t) & ~TYPE_ENDIANNESS_MASK)
+#define TYPE_MODIFIERS(t) ((t) & ~0xFF)
#define TYPE_NO_MODIFIERS(t) ((t) & 0xFF)
+#define ENDIANNESS_ALLOWED_TYPES "sSiIlLqQjJfFdDpP("
+
#define DO_BO_UNPACK(var, type) \
STMT_START { \
- switch (datumtype & TYPE_ENDIANNESS_MASK) { \
+ switch (TYPE_ENDIANNESS(datumtype)) { \
case TYPE_IS_BIG_ENDIAN: var = my_betoh ## type (var); break; \
case TYPE_IS_LITTLE_ENDIAN: var = my_letoh ## type (var); break; \
default: break; \
@@ -137,7 +142,7 @@ S_mul128(pTHX_ SV *sv, U8 m)
#define DO_BO_PACK(var, type) \
STMT_START { \
- switch (datumtype & TYPE_ENDIANNESS_MASK) { \
+ switch (TYPE_ENDIANNESS(datumtype)) { \
case TYPE_IS_BIG_ENDIAN: var = my_htobe ## type (var); break; \
case TYPE_IS_LITTLE_ENDIAN: var = my_htole ## type (var); break; \
default: break; \
@@ -146,7 +151,7 @@ S_mul128(pTHX_ SV *sv, U8 m)
#define DO_BO_UNPACK_PTR(var, type, pre_cast) \
STMT_START { \
- switch (datumtype & TYPE_ENDIANNESS_MASK) { \
+ switch (TYPE_ENDIANNESS(datumtype)) { \
case TYPE_IS_BIG_ENDIAN: \
var = (void *) my_betoh ## type ((pre_cast) var); \
break; \
@@ -160,7 +165,7 @@ S_mul128(pTHX_ SV *sv, U8 m)
#define DO_BO_PACK_PTR(var, type, pre_cast) \
STMT_START { \
- switch (datumtype & TYPE_ENDIANNESS_MASK) { \
+ switch (TYPE_ENDIANNESS(datumtype)) { \
case TYPE_IS_BIG_ENDIAN: \
var = (void *) my_htobe ## type ((pre_cast) var); \
break; \
@@ -173,8 +178,8 @@ S_mul128(pTHX_ SV *sv, U8 m)
} STMT_END
#define BO_CANT_DOIT(action, type) \
- STMT_START { \
- switch (datumtype & TYPE_ENDIANNESS_MASK) { \
+ STMT_START { \
+ switch (TYPE_ENDIANNESS(datumtype)) { \
case TYPE_IS_BIG_ENDIAN: \
Perl_croak(aTHX_ "Can't %s big-endian %ss on this " \
"platform", #action, #type); \
@@ -203,7 +208,7 @@ S_mul128(pTHX_ SV *sv, U8 m)
defined(my_htoben) && defined(my_betohn)
# define DO_BO_UNPACK_N(var, type) \
STMT_START { \
- switch (datumtype & TYPE_ENDIANNESS_MASK) { \
+ switch (TYPE_ENDIANNESS(datumtype)) { \
case TYPE_IS_BIG_ENDIAN: my_betohn(&var, sizeof(type)); break;\
case TYPE_IS_LITTLE_ENDIAN: my_letohn(&var, sizeof(type)); break;\
default: break; \
@@ -212,7 +217,7 @@ S_mul128(pTHX_ SV *sv, U8 m)
# define DO_BO_PACK_N(var, type) \
STMT_START { \
- switch (datumtype & TYPE_ENDIANNESS_MASK) { \
+ switch (TYPE_ENDIANNESS(datumtype)) { \
case TYPE_IS_BIG_ENDIAN: my_htoben(&var, sizeof(type)); break;\
case TYPE_IS_LITTLE_ENDIAN: my_htolen(&var, sizeof(type)); break;\
default: break; \
@@ -480,6 +485,7 @@ S_next_symbol(pTHX_ register tempsym_t* symptr )
} else {
/* We should have found a template code */
I32 code = *patptr++ & 0xFF;
+ U32 inherited_modifiers = 0;
if (code == ','){ /* grandfather in commas but with a warning */
if (((symptr->flags & FLAG_COMMA) == 0) && ckWARN(WARN_UNPACK)){
@@ -503,6 +509,12 @@ S_next_symbol(pTHX_ register tempsym_t* symptr )
symptr->flags & FLAG_PACK ? "pack" : "unpack" );
}
+ /* look for group modifiers to inherit */
+ if (TYPE_ENDIANNESS(symptr->flags)) {
+ if (strchr(ENDIANNESS_ALLOWED_TYPES, TYPE_NO_MODIFIERS(code)))
+ inherited_modifiers |= TYPE_ENDIANNESS(symptr->flags);
+ }
+
/* look for modifiers */
while (patptr < patend) {
const char *allowed;
@@ -514,24 +526,32 @@ S_next_symbol(pTHX_ register tempsym_t* symptr )
break;
case '>':
modifier = TYPE_IS_BIG_ENDIAN;
- allowed = "sSiIlLqQjJfFdDpP";
+ allowed = ENDIANNESS_ALLOWED_TYPES;
break;
case '<':
modifier = TYPE_IS_LITTLE_ENDIAN;
- allowed = "sSiIlLqQjJfFdDpP";
+ allowed = ENDIANNESS_ALLOWED_TYPES;
break;
default:
break;
}
+
if (modifier == 0)
break;
+
if (!strchr(allowed, TYPE_NO_MODIFIERS(code)))
Perl_croak(aTHX_ "'%c' allowed only after types %s in %s", *patptr,
allowed, symptr->flags & FLAG_PACK ? "pack" : "unpack" );
- if ((code | modifier) == (code | TYPE_IS_BIG_ENDIAN | TYPE_IS_LITTLE_ENDIAN))
+
+ if (TYPE_ENDIANNESS(code | modifier) == TYPE_ENDIANNESS_MASK)
Perl_croak(aTHX_ "Can't use both '<' and '>' after type '%c' in %s",
(int) TYPE_NO_MODIFIERS(code),
symptr->flags & FLAG_PACK ? "pack" : "unpack" );
+ else if (TYPE_ENDIANNESS(code | modifier | inherited_modifiers) ==
+ TYPE_ENDIANNESS_MASK)
+ Perl_croak(aTHX_ "Can't use '%c' in a group with different byte-order in %s",
+ *patptr, symptr->flags & FLAG_PACK ? "pack" : "unpack" );
+
if (ckWARN(WARN_UNPACK)) {
if (code & modifier)
Perl_warner(aTHX_ packWARN(WARN_UNPACK),
@@ -539,10 +559,14 @@ S_next_symbol(pTHX_ register tempsym_t* symptr )
*patptr, (int) TYPE_NO_MODIFIERS(code),
symptr->flags & FLAG_PACK ? "pack" : "unpack" );
}
+
code |= modifier;
patptr++;
}
+ /* inherit modifiers */
+ code |= inherited_modifiers;
+
/* look for count and/or / */
if (patptr < patend) {
if (isDIGIT(*patptr)) {
@@ -586,11 +610,11 @@ S_next_symbol(pTHX_ register tempsym_t* symptr )
if (patptr < patend)
patptr++;
} else {
- if( *patptr == '/' ){
+ if (*patptr == '/') {
symptr->flags |= FLAG_SLASH;
patptr++;
- if( patptr < patend &&
- (isDIGIT(*patptr) || *patptr == '*' || *patptr == '[') )
+ if (patptr < patend &&
+ (isDIGIT(*patptr) || *patptr == '*' || *patptr == '['))
Perl_croak(aTHX_ "'/' does not take a repeat count in %s",
symptr->flags & FLAG_PACK ? "pack" : "unpack" );
}
@@ -739,6 +763,8 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c
{
char *ss = s; /* Move from register */
tempsym_t savsym = *symptr;
+ U32 group_modifiers = TYPE_MODIFIERS(datumtype & ~symptr->flags);
+ symptr->flags |= group_modifiers;
symptr->patend = savsym.grpend;
symptr->level++;
PUTBACK;
@@ -750,6 +776,7 @@ S_unpack_rec(pTHX_ register tempsym_t* symptr, register char *s, char *strbeg, c
}
SPAGAIN;
s = ss;
+ symptr->flags &= ~group_modifiers;
savsym.flags = symptr->flags;
*symptr = savsym;
break;
@@ -2252,6 +2279,8 @@ S_pack_rec(pTHX_ SV *cat, register tempsym_t* symptr, register SV **beglist, SV
case '(':
{
tempsym_t savsym = *symptr;
+ U32 group_modifiers = TYPE_MODIFIERS(datumtype & ~symptr->flags);
+ symptr->flags |= group_modifiers;
symptr->patend = savsym.grpend;
symptr->level++;
while (len--) {
@@ -2260,6 +2289,7 @@ S_pack_rec(pTHX_ SV *cat, register tempsym_t* symptr, register SV **beglist, SV
if (savsym.howlen == e_star && beglist == endlist)
break; /* No way to continue */
}
+ symptr->flags &= ~group_modifiers;
lookahead.flags = symptr->flags;
*symptr = savsym;
break;