summaryrefslogtreecommitdiffstats
path: root/scripts/unanon
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/unanon')
-rwxr-xr-xscripts/unanon50
1 files changed, 50 insertions, 0 deletions
diff --git a/scripts/unanon b/scripts/unanon
new file mode 100755
index 0000000..2bbb3c8
--- /dev/null
+++ b/scripts/unanon
@@ -0,0 +1,50 @@
+#!/usr/bin/env perl
+#
+# Post-process files generated by protoc-c to remove anonymous unions.
+# Works on the generated files but probably little else.
+
+use warnings;
+use strict;
+
+sub unanon {
+ my $hfile = shift;
+ my $cfile = shift;
+ my ($fh, $content);
+ my %members;
+
+ open $fh, "<", $hfile or die $!;
+ local $/; # enable localized slurp mode
+ $content = <$fh>;
+ close $fh;
+
+ # Detect and replace anonymous unions in .h file.
+ # Assumes there is only one anonymous union in scope.
+ while ($content =~ s/^(struct\s+(\w+)[^}]+)(union\s+{([^}]+)}\s*);/$1$3 u;/sm) {
+ my $s = $2;
+ my $u = $4;
+ $u =~ s:/\*((?!\*/).)*\*/::sg;
+ foreach (split(/\n+/, $u)) {
+ if (/^.*\s+\**([^;]+);/) {
+ $members{$1} = $s;
+ }
+ }
+ }
+ open $fh, ">", $hfile or die $!;
+ print $fh $content;
+ close $fh;
+
+ # Replace anonymous union access in generated .c file.
+ open $fh, "<", $cfile or die $!;
+ $content = <$fh>;
+ close $fh;
+
+ while (my ($key, $val) = each %members) {
+ # We only support access via offsetof()
+ $content =~ s/offsetof\($val, $key\)/offsetof($val, u.$key)/g;
+ }
+ open $fh, ">", $cfile or die $!;
+ print $fh $content;
+ close $fh;
+}
+
+unanon(@ARGV);