Bug 617947 - glib-mkenums: add @valuenum@ support

Add a @valuenum@ substitution that outputs the integer value of a
particular enum value.  The value is determined by using (sandboxed)
perl to evaluate C expression.  If evaluation fails then glib-mkenums
dies loudly.  Evaluation is only enabled if '@valuenum@' appears in the
template file, so existing users will not be affected.
This commit is contained in:
Ryan Lortie 2010-05-06 14:19:58 -05:00
parent 7aa71527e5
commit 47805f4e0c

View File

@ -1,6 +1,7 @@
#!@PERL_PATH@ -w #!@PERL_PATH@ -w
use File::Basename; use File::Basename;
use Safe;
# glib-mkenums.pl # glib-mkenums.pl
# Information about the current enumeration # Information about the current enumeration
@ -21,6 +22,7 @@ my $enumname_prefix; # prefix of $enumname
my $enumindex = 0; # Global enum counter my $enumindex = 0; # Global enum counter
my $firstenum = 1; # Is this the first enumeration per file? my $firstenum = 1; # Is this the first enumeration per file?
my @entries; # [ $name, $val ] for each entry my @entries; # [ $name, $val ] for each entry
my $sandbox = Safe->new; # sandbox for safe evaluation of expressions
sub parse_trigraph { sub parse_trigraph {
my $opts = shift; my $opts = shift;
@ -110,10 +112,10 @@ sub parse_entries {
if (defined $options) { if (defined $options) {
my %options = parse_trigraph($options); my %options = parse_trigraph($options);
if (!defined $options{skip}) { if (!defined $options{skip}) {
push @entries, [ $name, $options{nick} ]; push @entries, [ $name, $value, $options{nick} ];
} }
} else { } else {
push @entries, [ $name ]; push @entries, [ $name, $value ];
} }
} elsif (m@^\s*\#@) { } elsif (m@^\s*\#@) {
# ignore preprocessor directives # ignore preprocessor directives
@ -158,6 +160,7 @@ sub usage {
print " \@ENUMPREFIX\@ PREFIX\n"; print " \@ENUMPREFIX\@ PREFIX\n";
print " \@VALUENAME\@ PREFIX_THE_XVALUE\n"; print " \@VALUENAME\@ PREFIX_THE_XVALUE\n";
print " \@valuenick\@ the-xvalue\n"; print " \@valuenick\@ the-xvalue\n";
print " \@valuenum\@ the integer value (limited support, Since: 2.26)\n";
print " \@type\@ either enum or flags\n"; print " \@type\@ either enum or flags\n";
print " \@Type\@ either Enum or Flags\n"; print " \@Type\@ either Enum or Flags\n";
print " \@TYPE\@ either ENUM or FLAGS\n"; print " \@TYPE\@ either ENUM or FLAGS\n";
@ -331,7 +334,7 @@ while (<>) {
# Autogenerate a prefix # Autogenerate a prefix
if (!defined $enum_prefix) { if (!defined $enum_prefix) {
for (@entries) { for (@entries) {
my $nick = $_->[1]; my $nick = $_->[2];
if (!defined $nick) { if (!defined $nick) {
my $name = $_->[0]; my $name = $_->[0];
if (defined $enum_prefix) { if (defined $enum_prefix) {
@ -357,12 +360,12 @@ while (<>) {
} }
for $entry (@entries) { for $entry (@entries) {
my ($name,$nick) = @{$entry}; my ($name,$num,$nick) = @{$entry};
if (!defined $nick) { if (!defined $nick) {
($nick = $name) =~ s/^$enum_prefix//; ($nick = $name) =~ s/^$enum_prefix//;
$nick =~ tr/_/-/; $nick =~ tr/_/-/;
$nick = lc($nick); $nick = lc($nick);
@{$entry} = ($name, $nick); @{$entry} = ($name, $num, $nick);
} }
} }
@ -454,13 +457,34 @@ while (<>) {
if (length($vprod)) { if (length($vprod)) {
my $prod = $vprod; my $prod = $vprod;
my $next_num = 0;
$prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g; $prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
$prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g; $prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
for (@entries) { for (@entries) {
my ($name,$nick) = @{$_}; my ($name,$num,$nick) = @{$_};
my $tmp_prod = $prod; my $tmp_prod = $prod;
if ($prod =~ /\@valuenum\@/) {
# only attempt to eval the value if it is requested
# this prevents us from throwing errors otherwise
if (defined $num) {
# use sandboxed perl evaluation as a reasonable
# approximation to C constant folding
$num = $sandbox->reval ($num);
# make sure it parsed to an integer
if (!defined $num or $num !~ /^-?\d+$/) {
die "Unable to parse enum value '$num'";
}
} else {
$num = $next_num;
}
$tmp_prod =~ s/\@valuenum\@/$num/g;
$next_num = $num + 1;
}
$tmp_prod =~ s/\@VALUENAME\@/$name/g; $tmp_prod =~ s/\@VALUENAME\@/$name/g;
$tmp_prod =~ s/\@valuenick\@/$nick/g; $tmp_prod =~ s/\@valuenick\@/$nick/g;
if ($flags) { $tmp_prod =~ s/\@type\@/flags/g; } else { $tmp_prod =~ s/\@type\@/enum/g; } if ($flags) { $tmp_prod =~ s/\@type\@/flags/g; } else { $tmp_prod =~ s/\@type\@/enum/g; }