-#!@PERL_PATH@ -w
+#! @PERL_PATH@
+
+use warnings;
+use File::Basename;
+use Safe;
# glib-mkenums.pl
# Information about the current enumeration
my $enum_prefix; # Prefix for this enumeration
my $enumname; # Name for this enumeration
my $enumshort; # $enumname without prefix
+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;
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
exit 0;
}
sub usage {
- print "Usage: glib-mkenums [options] [files...]\n";
- print " --fhead <text> output file header\n";
- print " --fprod <text> per input file production\n";
- print " --ftail <text> output file trailer\n";
- print " --eprod <text> per enum text (produced prior to value itarations)\n";
- print " --vhead <text> value header, produced before iterating over enum values\n";
- print " --vprod <text> value text, produced for each enum value\n";
- print " --vtail <text> value tail, produced after iterating over enum values\n";
- print " --comments <text> comment structure\n";
- print " --template file template file\n";
- print " -h, --help show this help message\n";
- print " -v, --version print version informations\n";
+ print "Usage:\n";
+ print " glib-mkenums [OPTION...] [FILES...]\n\n";
+ print "Help Options:\n";
+ print " -h, --help Show this help message\n\n";
+ print "Utility Options:\n";
+ print " --identifier-prefix <text> Identifier prefix\n";
+ print " --symbol-prefix <text> Symbol prefix\n";
+ print " --fhead <text> Output file header\n";
+ print " --fprod <text> Per input file production\n";
+ print " --ftail <text> Output file trailer\n";
+ print " --eprod <text> Per enum text (produced prior to value itarations)\n";
+ print " --vhead <text> Value header, produced before iterating over enum values\n";
+ print " --vprod <text> Value text, produced for each enum value\n";
+ print " --vtail <text> Value tail, produced after iterating over enum values\n";
+ print " --comments <text> Comment structure\n";
+ print " --template file Template file\n";
+ print " -v, --version Print version informations\n\n";
print "Production text substitutions:\n";
- print " \@EnumName\@ PrefixTheXEnum\n";
- print " \@enum_name\@ prefix_the_xenum\n";
- print " \@ENUMNAME\@ PREFIX_THE_XENUM\n";
- print " \@ENUMSHORT\@ THE_XENUM\n";
- print " \@VALUENAME\@ PREFIX_THE_XVALUE\n";
- print " \@valuenick\@ the-xvalue\n";
- print " \@type\@ either enum or flags\n";
- print " \@Type\@ either Enum or Flags\n";
- print " \@TYPE\@ either ENUM or FLAGS\n";
- print " \@filename\@ name of current input file\n";
+ print " \@EnumName\@ PrefixTheXEnum\n";
+ print " \@enum_name\@ prefix_the_xenum\n";
+ print " \@ENUMNAME\@ PREFIX_THE_XENUM\n";
+ print " \@ENUMSHORT\@ THE_XENUM\n";
+ 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";
+ print " \@filename\@ name of current input file\n";
+ print " \@basename\@ base name of the current input file (Since: 2.22)\n";
exit 0;
}
# production variables:
+my $idprefix = ""; # "G", "Gtk", etc
+my $symprefix = ""; # "g", "gtk", etc, if not just lc($idprefix)
my $fhead = ""; # output file header
my $fprod = ""; # per input file production
my $ftail = ""; # output file trailer
my $vhead = ""; # value header, produced before iterating over enum values
my $vprod = ""; # value text, produced for each enum value
my $vtail = ""; # value tail, produced after iterating over enum values
-# other options
-my $comment_tmpl = "/* \@comment\@ */";
+my $comment_tmpl = ""; # comment template
sub read_template_file {
my ($file) = @_;
$vprod = $tmpl{'value-production'};
$vtail = $tmpl{'value-tail'};
$comment_tmpl = $tmpl{'comment'};
+
+ # default to C-style comments
+ $comment_tmpl = "/* \@comment\@ */" if $comment_tmpl eq "";
}
if (!defined $ARGV[0]) {
while ($_=$ARGV[0],/^-/) {
shift;
last if /^--$/;
- if (/^--template$/) { read_template_file (shift); }
- elsif (/^--fhead$/) { $fhead = $fhead . shift }
- elsif (/^--fprod$/) { $fprod = $fprod . shift }
- elsif (/^--ftail$/) { $ftail = $ftail . shift }
- elsif (/^--eprod$/) { $eprod = $eprod . shift }
- elsif (/^--vhead$/) { $vhead = $vhead . shift }
- elsif (/^--vprod$/) { $vprod = $vprod . shift }
- elsif (/^--vtail$/) { $vtail = $vtail . shift }
- elsif (/^--comments$/) { $comment_tmpl = shift }
- elsif (/^--help$/ || /^-h$/) { usage; }
- elsif (/^--version$/ || /^-v$/) { version; }
+ if (/^--template$/) { read_template_file (shift); }
+ elsif (/^--identifier-prefix$/) { $idprefix = shift }
+ elsif (/^--symbol-prefix$/) { $symprefix = shift }
+ elsif (/^--fhead$/) { $fhead = $fhead . shift }
+ elsif (/^--fprod$/) { $fprod = $fprod . shift }
+ elsif (/^--ftail$/) { $ftail = $ftail . shift }
+ elsif (/^--eprod$/) { $eprod = $eprod . shift }
+ elsif (/^--vhead$/) { $vhead = $vhead . shift }
+ elsif (/^--vprod$/) { $vprod = $vprod . shift }
+ elsif (/^--vtail$/) { $vtail = $vtail . shift }
+ elsif (/^--comments$/) { $comment_tmpl = shift }
+ elsif (/^--help$/ || /^-h$/ || /^-\?$/) { usage; }
+ elsif (/^--version$/ || /^-v$/) { version; }
else { usage; }
last if not defined($ARGV[0]);
}
if (length($fhead)) {
my $prod = $fhead;
+ my $base = basename ($ARGV[0]);
$prod =~ s/\@filename\@/$ARGV[0]/g;
+ $prod =~ s/\@basename\@/$base/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;
chomp ($prod);
([^*]+|\*(?!/))*
\*/@@gx;
+ # ignore forward declarations
+ next if /^\s*typedef\s+enum.*;/;
+
if (m@^\s*typedef\s+enum\s*
({)?\s*
(?:/\*<
# Didn't have trailing '{' look on next lines
if (!defined $1 && !defined $4) {
while (<>) {
+ if (eof) {
+ die "Hit end of file while parsing enum in $ARGV";
+ }
if (s/^\s*\{//) {
last;
}
# 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) {
}
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);
}
}
$enumsym = lc $option_underscore_name;
$enumshort = $enumlong;
$enumshort =~ s/^[A-Z][A-Z0-9]*_//;
- } else {
+
+ $enumname_prefix = $enumlong;
+ $enumname_prefix =~ s/_$enumshort$//;
+ } elsif (!$symprefix && !$idprefix) {
# enumname is e.g. GMatchType
$enspace = $enumname;
$enspace =~ s/^([A-Z][a-z]*).*$/$1/;
$enumshort =~ s/([A-Z][A-Z])([A-Z][0-9a-z])/$1_$2/g;
$enumshort = uc($enumshort);
+ $enumname_prefix = $enumname;
+ $enumname_prefix =~ s/^([A-Z][a-z]*).*$/$1/;
+ $enumname_prefix = uc($enumname_prefix);
+
$enumlong = uc($enspace) . "_" . $enumshort;
$enumsym = lc($enspace) . "_" . lc($enumshort);
if (defined($option_lowercase_name)) {
$enumsym = $option_lowercase_name;
}
+ } else {
+ $enumshort = $enumname;
+ if ($idprefix) {
+ $enumshort =~ s/^${idprefix}//;
+ } else {
+ $enumshort =~ s/^[A-Z][a-z]*//;
+ }
+ $enumshort =~ s/([^A-Z])([A-Z])/$1_$2/g;
+ $enumshort =~ s/([A-Z][A-Z])([A-Z][0-9a-z])/$1_$2/g;
+ $enumshort = uc($enumshort);
+
+ $enumname_prefix = $symprefix && uc($symprefix) || uc($idprefix);
+
+ $enumlong = $enumname_prefix . "_" . $enumshort;
+ $enumsym = lc($enumlong);
}
if ($firstenum) {
if (length($fprod)) {
my $prod = $fprod;
+ my $base = basename ($ARGV);
$prod =~ s/\@filename\@/$ARGV/g;
+ $prod =~ s/\@basename\@/$base/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;
chomp ($prod);
$prod =~ s/\@EnumName\@/$enumname/g;
$prod =~ s/\@ENUMSHORT\@/$enumshort/g;
$prod =~ s/\@ENUMNAME\@/$enumlong/g;
+ $prod =~ s/\@ENUMPREFIX\@/$enumname_prefix/g;
if ($flags) { $prod =~ s/\@type\@/flags/g; } else { $prod =~ s/\@type\@/enum/g; }
if ($flags) { $prod =~ s/\@Type\@/Flags/g; } else { $prod =~ s/\@Type\@/Enum/g; }
if ($flags) { $prod =~ s/\@TYPE\@/FLAGS/g; } else { $prod =~ s/\@TYPE\@/ENUM/g; }
$prod =~ s/\@EnumName\@/$enumname/g;
$prod =~ s/\@ENUMSHORT\@/$enumshort/g;
$prod =~ s/\@ENUMNAME\@/$enumlong/g;
+ $prod =~ s/\@ENUMPREFIX\@/$enumname_prefix/g;
if ($flags) { $prod =~ s/\@type\@/flags/g; } else { $prod =~ s/\@type\@/enum/g; }
if ($flags) { $prod =~ s/\@Type\@/Flags/g; } else { $prod =~ s/\@Type\@/Enum/g; }
if ($flags) { $prod =~ s/\@TYPE\@/FLAGS/g; } else { $prod =~ s/\@TYPE\@/ENUM/g; }
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; }
$prod =~ s/\@EnumName\@/$enumname/g;
$prod =~ s/\@ENUMSHORT\@/$enumshort/g;
$prod =~ s/\@ENUMNAME\@/$enumlong/g;
+ $prod =~ s/\@ENUMPREFIX\@/$enumname_prefix/g;
if ($flags) { $prod =~ s/\@type\@/flags/g; } else { $prod =~ s/\@type\@/enum/g; }
if ($flags) { $prod =~ s/\@Type\@/Flags/g; } else { $prod =~ s/\@Type\@/Enum/g; }
if ($flags) { $prod =~ s/\@TYPE\@/FLAGS/g; } else { $prod =~ s/\@TYPE\@/ENUM/g; }
if (length($ftail)) {
my $prod = $ftail;
+ my $base = basename ($ARGV);
$prod =~ s/\@filename\@/$ARGV/g;
+ $prod =~ s/\@basename\@/$base/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;
chomp ($prod);