--- /dev/null
+#!/usr/bin/perl -w
+# I'm assuming that you're running this on some kind of ASCII system, but
+# it will generate EDCDIC too. (TODO)
+use strict;
+use Encode;
+
+my @lines = grep {!/^#/} <DATA>;
+
+sub addline {
+ my ($arrays, $chrmap, $letter, $arrayname, $noone, $nocsum, $size) = @_;
+ my $line = "/* $letter */ $size";
+ $line .= " | PACK_SIZE_CANNOT_ONLY_ONE" if $noone;
+ $line .= " | PACK_SIZE_CANNOT_CSUM" if $nocsum;
+ $line .= ",";
+ $arrays->{$arrayname}->[ord $chrmap->{$letter}] = $line;
+ # print ord $chrmap->{$letter}, " $line\n";
+}
+
+sub output_tables {
+ my %arrays;
+
+ my $chrmap = shift;
+ foreach (@_) {
+ my ($letter, $shriek, $noone, $nocsum, $size)
+ = /^([A-Za-z])(!?)\t(\S*)\t(\S*)\t(.*)/;
+ die "Can't parse '$_'" unless $size;
+
+ unless ($size =~ s/^=//) {
+ $size = "sizeof($size)";
+ }
+
+ addline (\%arrays, $chrmap, $letter, $shriek ? 'shrieking' : 'normal',
+ $noone, $nocsum, $size);
+ }
+
+ my %earliest;
+ foreach my $arrayname (sort keys %arrays) {
+ my $array = $arrays{$arrayname};
+ die "No defined entries in $arrayname" unless $array->[$#$array];
+ # Find the first used entry
+ my $earliest = 0;
+ $earliest++ while (!$array->[$earliest]);
+ # Remove all the empty elements.
+ splice @$array, 0, $earliest;
+ print "unsigned char size_${arrayname}[", scalar @$array, "] = {\n";
+ my @lines = map {$_ || "0,"} @$array;
+ # remove the last, annoying, comma
+ chop $lines[$#lines];
+ print " $_\n" foreach @lines;
+ print "};\n";
+ $earliest{$arrayname} = $earliest;
+ }
+
+ print "struct packsize_t packsize[2] = {\n";
+
+ my @lines;
+ foreach (qw(normal shrieking)) {
+ my $array = $arrays{$_};
+ push @lines, " {size_$_, $earliest{$_}, " . (scalar @$array) . "},";
+ }
+ # remove the last, annoying, comma
+ chop $lines[$#lines];
+ print "$_\n" foreach @lines;
+ print "};\n";
+}
+
+my %asciimap = (map {chr $_, chr $_} 0..255);
+my %ebcdicmap = (map {chr $_, Encode::encode ("posix-bc", chr $_)} 0..255);
+
+print <<'EOC';
+#if 'J'-'I' == 1
+/* ASCII */
+EOC
+output_tables (\%asciimap, @lines);
+print <<'EOC';
+#else
+/* EBCDIC (or bust) */
+EOC
+output_tables (\%ebcdicmap, @lines);
+print "#endif\n";
+
+__DATA__
+#Symbol nooone nocsum size
+c char
+C unsigned char
+U char
+s! short
+s =SIZE16
+S! unsigned short
+v =SIZE16
+n =SIZE16
+S =SIZE16
+v! =SIZE16
+n! =SIZE16
+i int
+i! int
+I unsigned int
+I! unsigned int
+j =IVSIZE
+J =UVSIZE
+l! long
+l =SIZE32
+L! unsigned long
+V =SIZE32
+N =SIZE32
+V! =SIZE32
+N! =SIZE32
+L =SIZE32
+p * * char *
+w * char
+q Quad_t
+Q Uquad_t
+f float
+d double
+F =NVSIZE
+D =LONG_DOUBLESIZE
# define DO_BO_PACK_N(var, type) BO_CANT_DOIT(pack, type)
#endif
+#define PACK_SIZE_CANNOT_CSUM 0x80
+#define PACK_SIZE_CANNOT_ONLY_ONE 0x40
+#define PACK_SIZE_MASK 0x3F
+
+
+struct packsize_t {
+ const char *array;
+ int first;
+ int size;
+};
+
+#define PACK_SIZE_NORMAL 0
+#define PACK_SIZE_SHRIEKING 1
+
+/* These tables are regenerated by genpacksizetables.pl (and then hand pasted
+ in). You're unlikely ever to need to regenerate them. */
+#if 'J'-'I' == 1
+/* ASCII */
+unsigned char size_normal[53] = {
+ /* C */ sizeof(unsigned char),
+ /* D */ LONG_DOUBLESIZE,
+ 0,
+ /* F */ NVSIZE,
+ 0, 0,
+ /* I */ sizeof(unsigned int),
+ /* J */ UVSIZE,
+ 0,
+ /* L */ SIZE32,
+ 0,
+ /* N */ SIZE32,
+ 0, 0,
+ /* Q */ sizeof(Uquad_t),
+ 0,
+ /* S */ SIZE16,
+ 0,
+ /* U */ sizeof(char),
+ /* V */ SIZE32,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* c */ sizeof(char),
+ /* d */ sizeof(double),
+ 0,
+ /* f */ sizeof(float),
+ 0, 0,
+ /* i */ sizeof(int),
+ /* j */ IVSIZE,
+ 0,
+ /* l */ SIZE32,
+ 0,
+ /* n */ SIZE16,
+ 0,
+ /* p */ sizeof(char *) | PACK_SIZE_CANNOT_ONLY_ONE | PACK_SIZE_CANNOT_CSUM,
+ /* q */ sizeof(Quad_t),
+ 0,
+ /* s */ SIZE16,
+ 0, 0,
+ /* v */ SIZE16,
+ /* w */ sizeof(char) | PACK_SIZE_CANNOT_CSUM
+};
+unsigned char size_shrieking[46] = {
+ /* I */ sizeof(unsigned int),
+ 0, 0,
+ /* L */ sizeof(unsigned long),
+ 0,
+ /* N */ SIZE32,
+ 0, 0, 0, 0,
+ /* S */ sizeof(unsigned short),
+ 0, 0,
+ /* V */ SIZE32,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* i */ sizeof(int),
+ 0, 0,
+ /* l */ sizeof(long),
+ 0,
+ /* n */ SIZE16,
+ 0, 0, 0, 0,
+ /* s */ sizeof(short),
+ 0, 0,
+ /* v */ SIZE16
+};
+struct packsize_t packsize[2] = {
+ {size_normal, 67, 53},
+ {size_shrieking, 73, 46}
+};
+#else
+/* EBCDIC (or bust) */
+unsigned char size_normal[99] = {
+ /* c */ sizeof(char),
+ /* d */ sizeof(double),
+ 0,
+ /* f */ sizeof(float),
+ 0, 0,
+ /* i */ sizeof(int),
+ 0, 0, 0, 0, 0, 0, 0,
+ /* j */ IVSIZE,
+ 0,
+ /* l */ SIZE32,
+ 0,
+ /* n */ SIZE16,
+ 0,
+ /* p */ sizeof(char *) | PACK_SIZE_CANNOT_ONLY_ONE | PACK_SIZE_CANNOT_CSUM,
+ /* q */ sizeof(Quad_t),
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* s */ SIZE16,
+ 0, 0,
+ /* v */ SIZE16,
+ /* w */ sizeof(char) | PACK_SIZE_CANNOT_CSUM,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ /* C */ sizeof(unsigned char),
+ /* D */ LONG_DOUBLESIZE,
+ 0,
+ /* F */ NVSIZE,
+ 0, 0,
+ /* I */ sizeof(unsigned int),
+ 0, 0, 0, 0, 0, 0, 0,
+ /* J */ UVSIZE,
+ 0,
+ /* L */ SIZE32,
+ 0,
+ /* N */ SIZE32,
+ 0, 0,
+ /* Q */ sizeof(Uquad_t),
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* S */ SIZE16,
+ 0,
+ /* U */ sizeof(char),
+ /* V */ SIZE32
+};
+unsigned char size_shrieking[93] = {
+ /* i */ sizeof(int),
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* l */ sizeof(long),
+ 0,
+ /* n */ SIZE16,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* s */ sizeof(short),
+ 0, 0,
+ /* v */ SIZE16,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* I */ sizeof(unsigned int),
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* L */ sizeof(unsigned long),
+ 0,
+ /* N */ SIZE32,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* S */ sizeof(unsigned short),
+ 0, 0,
+ /* V */ SIZE32
+};
+struct packsize_t packsize[2] = {
+ {size_normal, 131, 99},
+ {size_shrieking, 137, 93}
+};
+#endif
+
+
/* Returns the sizeof() struct described by pat */
STATIC I32
S_measure_struct(pTHX_ register tempsym_t* symptr)
len = (len + 1)/2;
size = 1;
break;
- case 's' | TYPE_IS_SHRIEKING:
-#if SHORTSIZE != SIZE16
- size = sizeof(short);
- break;
-#else
- /* FALL THROUGH */
-#endif
- case 's':
- size = SIZE16;
+
+
+ case 'P':
+ len = 1;
+ /* FALL THROUGH */
+ case 'p':
+ size = sizeof(char*);
break;
+
+ case 's' | TYPE_IS_SHRIEKING:
case 'S' | TYPE_IS_SHRIEKING:
-#if SHORTSIZE != SIZE16
- size = sizeof(unsigned short);
- break;
-#else
- /* FALL THROUGH */
-#endif
case 'v' | TYPE_IS_SHRIEKING:
case 'n' | TYPE_IS_SHRIEKING:
- case 'v':
- case 'n':
- case 'S':
- size = SIZE16;
- break;
case 'i' | TYPE_IS_SHRIEKING:
- case 'i':
- size = sizeof(int);
- break;
case 'I' | TYPE_IS_SHRIEKING:
- case 'I':
- size = sizeof(unsigned int);
- break;
- case 'j':
- size = IVSIZE;
- break;
- case 'J':
- size = UVSIZE;
- break;
case 'l' | TYPE_IS_SHRIEKING:
-#if LONGSIZE != SIZE32
- size = sizeof(long);
- break;
-#else
- /* FALL THROUGH */
-#endif
- case 'l':
- size = SIZE32;
- break;
case 'L' | TYPE_IS_SHRIEKING:
-#if LONGSIZE != SIZE32
- size = sizeof(unsigned long);
- break;
-#else
- /* FALL THROUGH */
-#endif
case 'V' | TYPE_IS_SHRIEKING:
case 'N' | TYPE_IS_SHRIEKING:
+ case 'i':
+ case 'I':
+ case 'j':
+ case 'J':
+ case 'l':
+ case 's':
+ case 'v':
+ case 'n':
+ case 'S':
case 'V':
case 'N':
case 'L':
- size = SIZE32;
- break;
- case 'P':
- len = 1;
- /* FALL THROUGH */
- case 'p':
- size = sizeof(char*);
- break;
#ifdef HAS_QUAD
case 'q':
- size = sizeof(Quad_t);
- break;
case 'Q':
- size = sizeof(Uquad_t);
- break;
#endif
case 'f':
- size = sizeof(float);
- break;
case 'd':
- size = sizeof(double);
- break;
case 'F':
- size = NVSIZE;
- break;
#if defined(HAS_LONG_DOUBLE) && defined(USE_LONG_DOUBLE)
case 'D':
- size = LONG_DOUBLESIZE;
- break;
#endif
+ {
+ int which = (symptr->code & TYPE_IS_SHRIEKING)
+ ? PACK_SIZE_SHRIEKING : PACK_SIZE_NORMAL;
+ int offset
+ = TYPE_NO_MODIFIERS(symptr->code) - packsize[which].first;
+ assert (offset >= 0);
+ assert (offset < packsize[which].size);
+ size = packsize[which].array[offset] & PACK_SIZE_MASK;
+ assert(size);
+ break;
+ }
}
total += len * size;
}
redo_switch:
beyond = s >= strend;
+ {
+ int which = (symptr->code & TYPE_IS_SHRIEKING)
+ ? PACK_SIZE_SHRIEKING : PACK_SIZE_NORMAL;
+ int offset = TYPE_NO_MODIFIERS(datumtype) - packsize[which].first;
+
+ if (offset >= 0 && offset < packsize[which].size) {
+ /* Data about this template letter */
+ unsigned char data = packsize[which].array[offset];
+
+ if (data) {
+ /* data nonzero means we can process this letter. */
+ long size = data & PACK_SIZE_MASK;
+ long howmany = (strend - s) / size;
+ if (len > howmany)
+ len = howmany;
+
+ if (!checksum || (data & PACK_SIZE_CANNOT_CSUM)) {
+ if (len && unpack_only_one &&
+ !(data & PACK_SIZE_CANNOT_ONLY_ONE))
+ len = 1;
+ EXTEND(SP, len);
+ EXTEND_MORTAL(len);
+ }
+ }
+ }
+ }
switch(TYPE_NO_ENDIANNESS(datumtype)) {
default:
Perl_croak(aTHX_ "Invalid type '%c' in unpack", (int)TYPE_NO_MODIFIERS(datumtype) );
XPUSHs(sv_2mortal(sv));
break;
case 'c':
- if (len > strend - s)
- len = strend - s;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
aint = *s++;
if (aint >= 128) /* fake up signed chars */
symptr->flags &= ~FLAG_UNPACK_DO_UTF8;
break;
}
- if (len > strend - s)
- len = strend - s;
if (checksum) {
uchar_checksum:
while (len-- > 0) {
}
}
else {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
while (len-- > 0) {
auint = *s++ & 255;
PUSHs(sv_2mortal(newSViv((IV)auint)));
}
if ((symptr->flags & FLAG_UNPACK_DO_UTF8) == 0)
goto unpack_C;
- if (len > strend - s)
- len = strend - s;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0 && s < strend) {
STRLEN alen;
auint = NATIVE_TO_UNI(utf8n_to_uvchr((U8*)s, strend - s, &alen, ckWARN(WARN_UTF8) ? 0 : UTF8_ALLOW_ANYUV));
break;
case 's' | TYPE_IS_SHRIEKING:
#if SHORTSIZE != SIZE16
- along = (strend - s) / sizeof(short);
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
COPYNN(s, &ashort, sizeof(short));
DO_BO_UNPACK(ashort, s);
/* Fallthrough! */
#endif
case 's':
- along = (strend - s) / SIZE16;
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
COPY16(s, &ai16);
DO_BO_UNPACK(ai16, 16);
break;
case 'S' | TYPE_IS_SHRIEKING:
#if SHORTSIZE != SIZE16
- along = (strend - s) / sizeof(unsigned short);
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
COPYNN(s, &aushort, sizeof(unsigned short));
DO_BO_UNPACK(aushort, s);
case 'v':
case 'n':
case 'S':
- along = (strend - s) / SIZE16;
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
COPY16(s, &au16);
DO_BO_UNPACK(au16, 16);
break;
case 'v' | TYPE_IS_SHRIEKING:
case 'n' | TYPE_IS_SHRIEKING:
- along = (strend - s) / SIZE16;
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
COPY16(s, &ai16);
s += SIZE16;
break;
case 'i':
case 'i' | TYPE_IS_SHRIEKING:
- along = (strend - s) / sizeof(int);
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
Copy(s, &aint, 1, int);
DO_BO_UNPACK(aint, i);
break;
case 'I':
case 'I' | TYPE_IS_SHRIEKING:
- along = (strend - s) / sizeof(unsigned int);
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
Copy(s, &auint, 1, unsigned int);
DO_BO_UNPACK(auint, i);
}
break;
case 'j':
- along = (strend - s) / IVSIZE;
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
Copy(s, &aiv, 1, IV);
#if IVSIZE == INTSIZE
}
break;
case 'J':
- along = (strend - s) / UVSIZE;
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
Copy(s, &auv, 1, UV);
#if UVSIZE == INTSIZE
break;
case 'l' | TYPE_IS_SHRIEKING:
#if LONGSIZE != SIZE32
- along = (strend - s) / sizeof(long);
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
COPYNN(s, &along, sizeof(long));
DO_BO_UNPACK(along, l);
/* Fallthrough! */
#endif
case 'l':
- along = (strend - s) / SIZE32;
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
COPY32(s, &ai32);
DO_BO_UNPACK(ai32, 32);
break;
case 'L' | TYPE_IS_SHRIEKING:
#if LONGSIZE != SIZE32
- along = (strend - s) / sizeof(unsigned long);
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
COPYNN(s, &aulong, sizeof(unsigned long));
DO_BO_UNPACK(aulong, l);
case 'V':
case 'N':
case 'L':
- along = (strend - s) / SIZE32;
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
COPY32(s, &au32);
DO_BO_UNPACK(au32, 32);
break;
case 'V' | TYPE_IS_SHRIEKING:
case 'N' | TYPE_IS_SHRIEKING:
- along = (strend - s) / SIZE32;
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
COPY32(s, &ai32);
s += SIZE32;
}
break;
case 'p':
- along = (strend - s) / sizeof(char*);
- if (len > along)
- len = along;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
while (len-- > 0) {
if (sizeof(char*) > strend - s)
break;
}
break;
case 'w':
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
{
UV auv = 0;
U32 bytes = 0;
break;
#ifdef HAS_QUAD
case 'q':
- along = (strend - s) / sizeof(Quad_t);
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
assert (s + sizeof(Quad_t) <= strend);
Copy(s, &aquad, 1, Quad_t);
}
break;
case 'Q':
- along = (strend - s) / sizeof(Uquad_t);
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
assert (s + sizeof(Uquad_t) <= strend);
Copy(s, &auquad, 1, Uquad_t);
#endif
/* float and double added gnb@melba.bby.oz.au 22/11/89 */
case 'f':
- along = (strend - s) / sizeof(float);
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
Copy(s, &afloat, 1, float);
DO_BO_UNPACK_N(afloat, float);
}
break;
case 'd':
- along = (strend - s) / sizeof(double);
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
Copy(s, &adouble, 1, double);
DO_BO_UNPACK_N(adouble, double);
}
break;
case 'F':
- along = (strend - s) / NVSIZE;
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
Copy(s, &anv, 1, NV);
DO_BO_UNPACK_N(anv, NV);
break;
#if defined(HAS_LONG_DOUBLE) && defined(USE_LONG_DOUBLE)
case 'D':
- along = (strend - s) / LONG_DOUBLESIZE;
- if (len > along)
- len = along;
- if (!checksum) {
- if (len && unpack_only_one)
- len = 1;
- EXTEND(SP, len);
- EXTEND_MORTAL(len);
- }
while (len-- > 0) {
Copy(s, &aldouble, 1, long double);
DO_BO_UNPACK_N(aldouble, long double);