1 |
#!/usr/bin/perl -w |
2 |
# I'm assuming that you're running this on some kind of ASCII system, but |
3 |
# it will generate EDCDIC too. (TODO) |
4 |
use strict; |
5 |
use Encode; |
6 |
|
7 |
my @lines = grep {!/^#/} <DATA>; |
8 |
|
9 |
sub addline { |
10 |
my ($arrays, $chrmap, $letter, $arrayname, $spare, $nocsum, $size, |
11 |
$condition) = @_; |
12 |
my $line = "/* $letter */ $size"; |
13 |
$line .= " | PACK_SIZE_SPARE" if $spare; |
14 |
$line .= " | PACK_SIZE_CANNOT_CSUM" if $nocsum; |
15 |
$line .= ","; |
16 |
# And then the hack |
17 |
$line = [$condition, $line] if $condition; |
18 |
$arrays->{$arrayname}->[ord $chrmap->{$letter}] = $line; |
19 |
# print ord $chrmap->{$letter}, " $line\n"; |
20 |
} |
21 |
|
22 |
sub output_tables { |
23 |
my %arrays; |
24 |
|
25 |
my $chrmap = shift; |
26 |
foreach (@_) { |
27 |
my ($letter, $shriek, $spare, $nocsum, $size, $condition) |
28 |
= /^([A-Za-z])(!?)\t(\S*)\t(\S*)\t([^\t\n]+)(?:\t+(.*))?$/; |
29 |
die "Can't parse '$_'" unless $size; |
30 |
|
31 |
if (defined $condition) { |
32 |
$condition = join " && ", map {"defined($_)"} split ' ', $condition; |
33 |
} |
34 |
unless ($size =~ s/^=//) { |
35 |
$size = "sizeof($size)"; |
36 |
} |
37 |
|
38 |
addline (\%arrays, $chrmap, $letter, $shriek ? 'shrieking' : 'normal', |
39 |
$spare, $nocsum, $size, $condition); |
40 |
} |
41 |
|
42 |
my %earliest; |
43 |
foreach my $arrayname (sort keys %arrays) { |
44 |
my $array = $arrays{$arrayname}; |
45 |
die "No defined entries in $arrayname" unless $array->[$#$array]; |
46 |
# Find the first used entry |
47 |
my $earliest = 0; |
48 |
$earliest++ while (!$array->[$earliest]); |
49 |
# Remove all the empty elements. |
50 |
splice @$array, 0, $earliest; |
51 |
print "unsigned char size_${arrayname}[", scalar @$array, "] = {\n"; |
52 |
my @lines; |
53 |
foreach (@$array) { |
54 |
# Remove the assumption here that the last entry isn't conditonal |
55 |
if (ref $_) { |
56 |
push @lines, |
57 |
["#if $_->[0]", " $_->[1]", "#else", " 0,", "#endif"]; |
58 |
} else { |
59 |
push @lines, $_ ? " $_" : " 0,"; |
60 |
} |
61 |
} |
62 |
# remove the last, annoying, comma |
63 |
my $last = $lines[$#lines]; |
64 |
my $got; |
65 |
foreach (ref $last ? @$last : $last) { |
66 |
$got += s/,$//; |
67 |
} |
68 |
die "Last entry had no commas" unless $got; |
69 |
print map {"$_\n"} ref $_ ? @$_ : $_ foreach @lines; |
70 |
print "};\n"; |
71 |
$earliest{$arrayname} = $earliest; |
72 |
} |
73 |
|
74 |
print "struct packsize_t packsize[2] = {\n"; |
75 |
|
76 |
my @lines; |
77 |
foreach (qw(normal shrieking)) { |
78 |
my $array = $arrays{$_}; |
79 |
push @lines, " {size_$_, $earliest{$_}, " . (scalar @$array) . "},"; |
80 |
} |
81 |
# remove the last, annoying, comma |
82 |
chop $lines[$#lines]; |
83 |
print "$_\n" foreach @lines; |
84 |
print "};\n"; |
85 |
} |
86 |
|
87 |
my %asciimap = (map {chr $_, chr $_} 0..255); |
88 |
my %ebcdicmap = (map {chr $_, Encode::encode ("posix-bc", chr $_)} 0..255); |
89 |
|
90 |
print <<'EOC'; |
91 |
#if 'J'-'I' == 1 |
92 |
/* ASCII */ |
93 |
EOC |
94 |
output_tables (\%asciimap, @lines); |
95 |
print <<'EOC'; |
96 |
#else |
97 |
/* EBCDIC (or bust) */ |
98 |
EOC |
99 |
output_tables (\%ebcdicmap, @lines); |
100 |
print "#endif\n"; |
101 |
|
102 |
__DATA__ |
103 |
#Symbol spare nocsum size |
104 |
c char |
105 |
C unsigned char |
106 |
U char |
107 |
s! short |
108 |
s =SIZE16 |
109 |
S! unsigned short |
110 |
v =SIZE16 |
111 |
n =SIZE16 |
112 |
S =SIZE16 |
113 |
v! =SIZE16 PERL_PACK_CAN_SHRIEKSIGN |
114 |
n! =SIZE16 PERL_PACK_CAN_SHRIEKSIGN |
115 |
i int |
116 |
i! int |
117 |
I unsigned int |
118 |
I! unsigned int |
119 |
j =IVSIZE |
120 |
J =UVSIZE |
121 |
l! long |
122 |
l =SIZE32 |
123 |
L! unsigned long |
124 |
V =SIZE32 |
125 |
N =SIZE32 |
126 |
V! =SIZE32 PERL_PACK_CAN_SHRIEKSIGN |
127 |
N! =SIZE32 PERL_PACK_CAN_SHRIEKSIGN |
128 |
L =SIZE32 |
129 |
p * char * |
130 |
w * char |
131 |
q Quad_t HAS_QUAD |
132 |
Q Uquad_t HAS_QUAD |
133 |
f float |
134 |
d double |
135 |
F =NVSIZE |
136 |
D =LONG_DOUBLESIZE HAS_LONG_DOUBLE USE_LONG_DOUBLE |