Bug 617947 - glib-mkenums: add @valuenum@ support
authorRyan Lortie <desrt@desrt.ca>
Thu, 6 May 2010 19:19:58 +0000 (14:19 -0500)
committerRyan Lortie <desrt@desrt.ca>
Thu, 6 May 2010 19:21:39 +0000 (14:21 -0500)
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.

gobject/glib-mkenums.in

index db4ebd3..a3cf558 100755 (executable)
@@ -1,6 +1,7 @@
 #!@PERL_PATH@ -w
 
 use File::Basename;
+use Safe;
 
 # glib-mkenums.pl 
 # Information about the current enumeration
@@ -21,6 +22,7 @@ my $enumname_prefix;          # prefix of $enumname
 my $enumindex = 0;             # Global enum counter
 my $firstenum = 1;             # Is this the first enumeration per file?
 my @entries;                   # [ $name, $val ] for each entry
+my $sandbox = Safe->new;        # sandbox for safe evaluation of expressions
 
 sub parse_trigraph {
     my $opts = shift;
@@ -110,10 +112,10 @@ sub parse_entries {
            if (defined $options) {
                my %options = parse_trigraph($options);
                if (!defined $options{skip}) {
-                   push @entries, [ $name, $options{nick} ];
+                   push @entries, [ $name, $value, $options{nick} ];
                }
            } else {
-               push @entries, [ $name ];
+               push @entries, [ $name, $value ];
            }
        } elsif (m@^\s*\#@) {
            # ignore preprocessor directives
@@ -158,6 +160,7 @@ sub usage {
     print "  \@ENUMPREFIX\@          PREFIX\n";
     print "  \@VALUENAME\@           PREFIX_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";
@@ -331,7 +334,7 @@ while (<>) {
        # Autogenerate a prefix
        if (!defined $enum_prefix) {
            for (@entries) {
-               my $nick = $_->[1];
+               my $nick = $_->[2];
                if (!defined $nick) {
                    my $name = $_->[0];
                    if (defined $enum_prefix) {
@@ -357,12 +360,12 @@ while (<>) {
        }
        
        for $entry (@entries) {
-           my ($name,$nick) = @{$entry};
+           my ($name,$num,$nick) = @{$entry};
             if (!defined $nick) {
                ($nick = $name) =~ s/^$enum_prefix//;
                $nick =~ tr/_/-/;
                $nick = lc($nick);
-               @{$entry} = ($name, $nick);
+               @{$entry} = ($name, $num, $nick);
             }
        }
        
@@ -454,13 +457,34 @@ while (<>) {
 
        if (length($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/\\f/\f/g; $prod =~ s/\\r/\r/g;
            for (@entries) {
-               my ($name,$nick) = @{$_};
+               my ($name,$num,$nick) = @{$_};
                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/\@valuenick\@/$nick/g;
                if ($flags) { $tmp_prod =~ s/\@type\@/flags/g; } else { $tmp_prod =~ s/\@type\@/enum/g; }