1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
#!/usr/bin/perl -w
# compresses messages for taipan.c.
# Reads lines from stdin of the form:
# label "message text"
# writes C code to stdout.
# by default, an asm include file "asm.inc" is created, containing
# definitions of messages which exactly match a dictionary entry.
# with -n, "asm.inc" is not created.
# with -d, dumps messages to be encoded, after dictionary replacement.
if(@ARGV) {
if($ARGV[0] eq '-n') {
$skip_msg_inc++;
} elsif($ARGV[0] eq '-d') {
$dump++;
$skip_msg_inc++;
}
}
# make dictionary from textdecomp.s comments
open my $t, "<textdecomp.s" or die $!;
while(<$t>) {
next unless /^dict(\d\d):.*;\s*"([^"]*)"/;
my $id = $1;
my $dictlabel = "dict$1";
if($id < 27) {
$id = chr($id + 96);
} else {
$id = chr($id - 27 + 65);
}
my $value = 'Z' . $id;
my $key = quotemeta $2;
$dictionary{$key} = $value;
$dictlabels{$value} = $dictlabel;
}
close $t;
#for(sort keys %dictionary) {
# warn "'$_' => $dictionary{$_}\n";
#}
#exit 0;
if(!$skip_msg_inc) {
open ASMINC, ">msg.inc" or die $!;
print ASMINC "; do not edit, contents are generated by messages.pl\n\n";
}
print "// do not edit, contents are generated by messages.pl\n\n";
while(<STDIN>) {
chomp;
$msgcount++;
/^(\w+)\s/;
my $label = $1;
s/^\w+\s+//;
my $orig = $_;
print " input: $_\n" if $dump;
s/"//g;
s/\\r//g;
s/\\n/\n/g;
$total_in += (1 + length);
my $dict_used = 0;
for my $dk (sort { length $b <=> length $a || $a cmp $b } keys %dictionary) {
if(s/$dk/$dictionary{$dk}/g) {
$dict_used = 1;
}
}
# if a string turns out to be exactly a dict entry, no need to include
# the compressed version in messages.c.
if(!$skip_msg_inc && /^Z.$/) {
print "\nextern const char M_$label\[\]; // dictionary used, $dictlabels{$_}\n\n";
print ASMINC " _M_$label = $dictlabels{$_}\n .export _M_$label\n\n";
next;
}
if($dump) {
my $w = $_;
$w =~ s/\n/\\n/g;
print "output: \"$w\"\n\n";
next;
}
open my $out, ">msg.out" or die $!;
print $out $_;
close $out;
system("./textcomp < msg.out > msg.tmp 2>/dev/null");
open my $result, "<msg.tmp" or die $!;
print "const char M_$label\[\] = {\n\t// $orig\n\t";
my $readbytes;
while(<$result>) {
my @got = split " ", $_;
$readbytes = @got;
print join(", ", @got);
$total_out += @got;
}
close $result;
die "failed to compress $orig\n" unless $readbytes;
print "\n};" . ($dict_used ? " // dictionary used" : "") . "\n\n";
}
close ASMINC unless $skip_msg_inc;
exit 0 if $dump;
print "// messages: $msgcount\n";
print "// total input size: $total_in\n";
print "// total output size: $total_out\n";
print "// compression: " . ($total_in - $total_out) . "\n";
print "// ratio: " . sprintf("%.1f", $total_out * 100 / $total_in) . "%\n";
# commented-out messages can go in the pod section below:
=pod
illion "illion" # somehow this wastes 2 bytes
fine "fine"
run "Run" # too short to be worth compression
how_much_spc "How much "
=cut
|