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 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
|
#!/usr/bin/perl -w
++$|;
END { print "\n\nPress enter to exit.\n"; <STDIN> }
use strict;
use warnings;
my ($source, $output);
for (@ARGV) {
# Note to self: "perl errorlist.pl --source=../../source/i18n --output=../../source/i18n/tests/ps/Errors.cpp"
if (/[-\/]\?|--\?|--help/) {
print <<EOH;
$0 parameters:
--source=../../source - root directory for source code
--output=../../source/ps/Errors.cpp - output file to generate
--help - route to enlightenment
EOH
exit;
} elsif (/^--source="?(.*?)"?$/) {
$source = $1;
} elsif (/^--output="?(.*?)"?$/) {
$output = $1;
}
}
$source ||= '../../source';
$output ||= "$source/ps/Errors.cpp";
print "Reading files from $source... ";
my (%topgroups, %groups, %types);
my @files = cpp_files("$source/");
my $loc = 0;
for (@files) {
open my $f, $_ or die "Error opening file '$_' ($!)";
while (<$f>) {
if (/^ERROR_/) {
if (/^ERROR_GROUP\((.+?)\)/) {
$topgroups{$1} = 1;
} elsif (/^ERROR_SUBGROUP\((.+?)\)/) {
$groups{join '~', split /,\s*/, $1} = 1;
} elsif (/^ERROR_TYPE\((.+?)\)/) {
$types{join '~', split /,\s*/, $1} = 1;
}
}
++$loc;
}
}
# Add commas to number in groups of three
1 while $loc =~ s/(\d+)(\d{3})/$1,$2/;
print "(".@files." files read - $loc lines of code)\n";
print "Generating $output... ";
# Add "PSERROR_Error_InvalidError", so that an error to throw when being
# told to throw an error that doesn't exist exists.
$topgroups{Error} = 1;
$types{'Error~InvalidError'} = 1;
open my $out, '>', "$output" or die "Error opening $output ($!)";
print $out <<'.';
// Auto-generated by errorlist.pl - do not edit.
#include "precompiled.h"
#include "Errors.h"
.
for (sort keys %topgroups) {
print $out "class PSERROR_$_ : public PSERROR { protected: PSERROR_$_(const char* msg); };\n";
}
print $out "\n";
for (sort { $a->[1] cmp $b->[1] } map [$_, do{(my $c=$_)=~s/~/_/;$c} ], keys %groups) {
my ($base, $name) = split /~/, $_->[0];
print $out "class PSERROR_${base}_$name : public PSERROR_$base { protected: PSERROR_${base}_$name(const char* msg); };\n";
}
print $out "\n";
for (sort { $a->[1] cmp $b->[1] } map [$_, do{(my $c=$_)=~s/~/_/;$c} ], keys %types) {
my ($base, $name) = split /~/, $_->[0];
print $out "class PSERROR_${base}_$name : public PSERROR_$base { public: PSERROR_${base}_$name(); PSERROR_${base}_$name(const char* msg); PSRETURN getCode() const; };\n";
}
print $out "\n";
# The difficult bit:
=pod
mask
**** PSERROR
0001 PSERROR_ Err1
1*** PSERROR_Sec1
1001 PSERROR_Sec1_ Err1
1002 PSERROR_Sec1_ Err2
1003 PSERROR_Sec1_ Err3
11** PSERROR_Sec1_Sec1
1101 PSERROR_Sec1_Sec1_Err1
1102 PSERROR_Sec1_Sec1_Err2
2*** PSERROR_Sec2
2001 PSERROR_Sec2_ Err1
...so split into three sections (0 if null) plus final code...
=cut
my @sec_codes;
$sec_codes[$_]{''} = 1 for 0..2;
for (keys %types) {
my (@secs) = split /[~_]/;
my $err = pop @secs;
$sec_codes[$_]{$secs[$_] || ''} = 1 for 0..2;
}
for my $n (0..2) {
@{$sec_codes[$n]}{sort keys %{$sec_codes[$n]}} = 0 .. keys(%{$sec_codes[$n]})-1;
}
my ($last_sec, $last_err) = ('', 0);
for (sort keys %types) {
my (@secs) = split /[~_]/;
my $err = pop @secs;
my $id = join '', map chr $sec_codes[$_]{$secs[$_] || ''}, 0..2;
if ($id eq $last_sec) {
$id .= chr(++$last_err);
} else {
$last_sec = $id;
$id .= chr($last_err=1);
}
$types{$_} = $id;
}
for (sort keys %types) {
my ($base, $name) = split /~/;
print $out "extern const PSRETURN PSRETURN_${base}_${name} = 0x".unpack('H*', $types{$_}).";\n";
}
print $out "\n";
for (sort keys %topgroups) {
my (@secs) = $_;
my $id = join '', map chr $sec_codes[$_]{$secs[$_] || ''}, 0..2;
my $code = unpack 'H*', $id;
(my $mask = $code) =~ s/(\d\d)/$1+0 ? 'ff' : '00'/ge;
print $out "extern const PSRETURN MASK__PSRETURN_".join('_', @secs)." = 0x${mask}00;\n";
print $out "extern const PSRETURN CODE__PSRETURN_".join('_', @secs)." = 0x${code}00;\n";
}
for (sort keys %groups) {
my (@secs) = split /[_~]/;
my $id = join '', map chr $sec_codes[$_]{$secs[$_] || ''}, 0..2;
my $code = unpack 'H*', $id;
(my $mask = $code) =~ s/(\d\d)/$1+0 ? 'ff' : '00'/ge;
print $out "extern const PSRETURN MASK__PSRETURN_".join('_', @secs)." = 0x${mask}00;\n";
print $out "extern const PSRETURN CODE__PSRETURN_".join('_', @secs)." = 0x${code}00;\n";
}
print $out "\n";
for (sort keys %types) {
my $code = unpack 'H*', $types{$_};
s/~/_/;
print $out "extern const PSRETURN MASK__PSRETURN_$_ = 0xffffffff;\n";
print $out "extern const PSRETURN CODE__PSRETURN_$_ = 0x$code;\n";
}
# End of difficult bit.
print $out "\n";
for (sort keys %topgroups) {
print $out "PSERROR_${_}::PSERROR_${_}(const char* msg) : PSERROR(msg) { }\n";
}
for (sort keys %groups) {
my ($base, $name) = split /~/;
print $out "PSERROR_${base}_${name}::PSERROR_${base}_${name}(const char* msg) : PSERROR_$base(msg) { }\n";
}
print $out "\n";
for (sort keys %types) {
my ($base, $name) = split /~/;
print $out "PSERROR_${base}_${name}::PSERROR_${base}_${name}() : PSERROR_$base(NULL) { }\n";
print $out "PSERROR_${base}_${name}::PSERROR_${base}_${name}(const char* msg) : PSERROR_$base(msg) { }\n";
print $out "PSRETURN PSERROR_${base}_${name}::getCode() const { return 0x".unpack('H*',$types{$_})."; }\n";
print $out "\n";
}
print $out <<".";
PSERROR::PSERROR(const char* msg) : m_msg(msg) { }
const char* PSERROR::what() const throw ()
{
return m_msg ? m_msg : GetErrorString(getCode());
}
const char* GetErrorString(PSRETURN code)
{
switch (code)
{
.
for (sort keys %types) {
(my $name = $_) =~ s/~/_/;
print $out qq{\tcase 0x}.unpack('H*',$types{$_}).qq{: return "$name";\n};
}
print $out <<".";
default: return "Unrecognised error";
}
}
void ThrowError(PSRETURN code)
{
switch (code) // Use 'break' in case someone tries to continue from the exception
{
.
for (sort keys %types) {
(my $name = $_) =~ s/~/_/;
print $out qq{\tcase 0x}.unpack('H*',$types{$_}).qq{: throw PSERROR_$name(); break;\n};
}
print $out <<".";
default: throw PSERROR_Error_InvalidError(); // Hmm...
}
}
.
print "Finished.\n";
sub cpp_files {
opendir my $d, $_[0] or die "Error opening directory '$_[0]' ($!)";
my @f = readdir $d;
my @files = map "$_[0]/$_", grep /\.(?:cpp|h)$/, @f;
push @files, cpp_files("$_[0]/$_") for grep { !/^(?:workspaces|tools)$/ and /^[a-zA-Z0-9]+$/ and -d "$_[0]/$_" } @f;
return @files;
}
|