aboutsummaryrefslogtreecommitdiff
path: root/messages.pl
blob: d00d9d5767ff8183db4d0562957ab61f205b7854 (plain)
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