#!/usr/bin/perl # enumsToPerl: # This Perl script creates a Perl version of the enum's that are in # the C/C++ header file supplied as the first command-line argument. # The second command-line argument specifies the filepath to the # module file that is to be created. # Sample usage: # perl enumsToPerl MyEnums.h MyEnums.pm # # Cameron Hayne (macdev@hayne.net) May 2009 use strict; use warnings; use File::Basename; # getEnumsFromString: sub getEnumsFromString($) { my ($str) = @_; # strip C & C++ style comments # (regex from: http://perldoc.perl.org/perlfaq6.html) $str =~ s#/\*[^*]*\*+([^/*][^*]*\*+)*/ |//[^\n]* |q("(\\.|[^"\\])*" | '(\\.|[^'\\])*' | .[^/"'\\]*) #defined $2 ? $2 : ""#gsex; my @enums = (); while ($str =~ /(enum\s+(\w+)\s*{([^}]*)}\s*;)/g) { my $enumDecl = $1; my $enumName = $2; my $enumBody = $3; my $enum = {}; $enum->{name} = $enumName; $enum->{pairs} = []; push(@enums, $enum); my $prevValue = -1; while ($enumBody =~ /(\w+)\s*(?:=\s*(.+))?,?/g) { my $name = $1; my $value = $2; if (defined($value)) { $value = eval($value); } else { $value = $prevValue + 1; } $prevValue = $value; push(@{$enum->{pairs}}, [$name, $value]); } } return @enums; } # writePerlCodeForEnums: sub writePerlCodeForEnums($$@) { my ($filehandle, $useHex, @enums) = @_; print $filehandle "# Enums:\n"; print $filehandle "# -----------------------------------------\n"; my $format = $useHex ? "\t'%s' => 0x%02x,\n" : "\t'%s' => %d,\n"; foreach my $enum (@enums) { my $enumName = $enum->{name}; print $filehandle "our %$enumName = (\n"; foreach my $pair (@{$enum->{pairs}}) { my $name = $pair->[0]; my $value = $pair->[1]; printf $filehandle ($format, $name, $value); } print $filehandle ");\n"; print $filehandle "\n"; } } # writePerlCodeForReverseEnums: sub writePerlCodeForReverseEnums($$@) { my ($filehandle, $useHex, @enums) = @_; print $filehandle "# Reverse Enums:\n"; print $filehandle "# -----------------------------------------\n"; my $format = $useHex ? "\t0x%02x => '%s',\n" : "\t%d => '%s',\n"; foreach my $enum (@enums) { my $enumName = $enum->{name} . "REVERSE"; print $filehandle "our %$enumName = (\n"; foreach my $pair (@{$enum->{pairs}}) { my $name = $pair->[0]; my $value = $pair->[1]; printf $filehandle ($format, $value, $name); } print $filehandle ");\n"; print $filehandle "\n"; } } sub writePerlCodeForModule($$$@) { my ($filehandle, $headerFile, $moduleName, @enums) = @_; my $time = localtime(); my $moduleStart = << "EOT"; # This Perl module was generated: $time # by using the 'enumsToPerl' script on the following header file: # $headerFile package $moduleName; EOT my $moduleCode = <<'EOT'; use Exporter; our @ISA = qw(Exporter); our @EXPORT = do { no strict 'refs'; map { '%' . $_ } keys %{ __PACKAGE__ . '::' }; }; EOT print $filehandle "$moduleStart\n"; print $filehandle "$moduleCode\n"; } # MAIN { die "Usage: enumsToPerl headerFile moduleFile\n" unless scalar(@ARGV) == 2; my $headerFile = $ARGV[0]; my $moduleFile = $ARGV[1]; die "Can't read header file '$headerFile'" unless -r $headerFile; my ($basename, $dirname, $ext) = fileparse($moduleFile, qr/\.[^.]*/); die "Can't create module file '$moduleFile'" unless -w $dirname; my $moduleName = $basename; undef $/; # slurp mode open(HEADERFILE, "< $headerFile") or die "Can't open header file '$headerFile' : $!\n"; my $contents = ; close(HEADERFILE) or die "Failed to close header file: $!\n"; open(MODULEFILE, "> $moduleFile") or die "Can't open module file '$moduleFile' for writing: $!\n"; my @enums = getEnumsFromString($contents); my $useHex = 1; writePerlCodeForModule(*MODULEFILE, $headerFile, $moduleName, @enums); writePerlCodeForEnums(*MODULEFILE, $useHex, @enums); writePerlCodeForReverseEnums(*MODULEFILE, $useHex, @enums); close(MODULEFILE) or die "Failed to close module file: $!\n"; }