enumgen.pl 6.13 KB
Newer Older
1 2
#!/usr/bin/perl -w

3
# GIMP - The GNU Image Manipulation Program
4
# Copyright (C) 1999-2003 Manish Singh <yosh@gimp.org>
5

6
# This program is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 3 of the License, or
9 10 11 12 13 14 15 16
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUTFILE ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
17
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
18 19

BEGIN {
20 21 22
    $srcdir   = $ENV{srcdir}   || '.';
    $destdir  = $ENV{destdir}   || '.';
    $builddir = $ENV{builddir} || '.';
23 24
}

Manish Singh's avatar
Manish Singh committed
25 26
use lib $srcdir;

27
use Text::Wrap qw(wrap $columns);
Manish Singh's avatar
Manish Singh committed
28
$columns = 77;
29

Elliot Lee's avatar
Elliot Lee committed
30 31
#BEGIN { require 'util.pl' }
require 'util.pl';
Manish Singh's avatar
Manish Singh committed
32 33 34 35

*write_file = \&Gimp::CodeGen::util::write_file;
*FILE_EXT   = \$Gimp::CodeGen::util::FILE_EXT;

36
my $header = <<'HEADER';
37
:# GIMP - The GNU Image Manipulation Program
38
:# Copyright (C) 1999-2003 Manish Singh <yosh@gimp.org>
39
:
40
:# This program is free software: you can redistribute it and/or modify
41
:# it under the terms of the GNU General Public License as published by
42
:# the Free Software Foundation; either version 3 of the License, or
43 44 45 46 47 48 49 50
:# (at your option) any later version.
:
:# This program is distributed in the hope that it will be useful,
:# but WITHOUTFILE ANY WARRANTY; without even the implied warranty of
:# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
:# GNU General Public License for more details.
:
:# You should have received a copy of the GNU General Public License
51
:# along with this program.  If not, see <https://www.gnu.org/licenses/>.
52 53 54 55 56 57 58 59
:
:# autogenerated by enumgen.pl
:
:package Gimp::CodeGen::enums;
:
:%enums = (
HEADER

60 61 62 63 64 65 66 67
my $external;
open my $EXTERNAL, "enums-external.pl";
{
    local $/;
    $external = <$EXTERNAL>;
}
close $EXTERNAL;

68 69 70 71 72
my $footer = <<'FOOTER';
:);
:
:foreach $e (values %enums) {
:    $e->{info} = "";
Manish Singh's avatar
Manish Singh committed
73
:    foreach (@{$e->{symbols}}) {
74
:	$e->{info} .= "$_ ($e->{mapping}->{$_}), "
Manish Singh's avatar
Manish Singh committed
75
:    }
76 77 78 79 80 81
:    $e->{info} =~ s/, $//;
:}
:
:1;
FOOTER

82
my ($enumname, $contig, $symbols, @mapping, $before);
83 84

# Most of this enum parsing stuff was swiped from makeenums.pl in GTK+
Manish Singh's avatar
Manish Singh committed
85 86 87 88 89
sub parse_options {
    my $opts = shift;
    my @opts;

    for $opt (split /\s*,\s*/, $opts) {
90 91 92
	$opt =~ s/^\s*//;
	$opt =~ s/\s*$//;
	my ($key,$val) = $opt =~ /([-\w]+)(?:=(.+))?/;
Manish Singh's avatar
Manish Singh committed
93 94 95 96 97 98
	defined $val or $val = 1;
	push @opts, $key, $val;
    }
    @opts;
}

99 100
sub parse_entries {
    my $file = shift;
101 102
    my $file_name = shift;
    my $looking_for_name = 0;
103 104 105

    while (<$file>) {
	# Read lines until we have no open comments
106
	while (m@/\*([^*]|\*(?!/))*$@) {
107
	    my $new;
108
	    defined ($new = <$file>) || die "Unmatched comment in $ARGV";
109 110
	    $_ .= $new;
	}
111
	# strip comments w/o options
112 113 114 115 116 117 118 119
	s@/\*(?!<)
	    ([^*]+|\*(?!/))*
	   \*/@@gx;
        
	s@\n@ @;
        
	next if m@^\s*$@;

120 121 122 123 124 125 126
	if ($looking_for_name) {
	    if (/^\s*(\w+)/) {
		$enumname = $1;
		return 1;
	    }
	}

127 128 129 130 131
	# Handle include files
	if (/^\#include\s*<([^>]*)>/ ) {
	    my $file= "../$1";
	    open NEWFILE, $file or die "Cannot open include file $file: $!\n";

132
	    if (&parse_entries (\*NEWFILE, $NEWFILE)) {
133 134 135 136 137 138 139 140 141 142 143
		return 1;
	    } else {
		next;
	    }
	}

	if (/^\s*\}\s*(\w+)/) {
	    $enumname = $1;
	    return 1;
	}

144 145 146 147 148
	if (/^\s*\}/) {
	    $looking_for_name = 1;
	    next;
	}

149 150 151 152 153 154 155
	if (m@^\s*
	      (\w+)\s*                   # name
	      (?:=(                      # value
		   (?:[^,/]|/(?!\*))*
		  ))?,?\s*
	      (?:/\*<                    # options 
		(([^*]|\*(?!/))*)
156
	       >\s*\*/)?,?
157 158
	      \s*$
             @x) {
Manish Singh's avatar
Manish Singh committed
159 160 161 162
            my ($name, $value, $options) = ($1, $2, $3);

	    if (defined $options) {
		my %options = parse_options($options);
163
		next if defined $options{"pdb-skip"};
164
	    }
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

	    $symbols .= $name . ' ';

	    # Figure out a default value (not really foolproof)
	    $value = $before + 1 if !defined $value;
	    $value =~ s/\s*$//s;
	    $value =~ s/^\s*//s;

	    push @mapping, $name, $value;

	    my $test = $before + 1;

	    # Warnings in our eval should be fatal so they set $@
	    local $SIG{__WARN__} = sub { die $_[0] };

	    # Try to get a numeric value
	    eval "\$test = $value * 1;";

	    # Assume noncontiguous if it's not a number
	    $contig = 0 if $contig && ($@ || $test - 1 != $before);

	    $before = $test;
187 188
	} elsif (m@^\s*\#@) {
	    # ignore preprocessor directives
189
        } else {
190
            print STDERR "$0: $file_name:$.: Failed to parse `$_'\n";
191 192 193 194 195 196 197 198 199 200 201
        }
    }
    return 0;
}

my $code = "";
while (<>) {
    if (eof) {
        close (ARGV);           # reset line numbering
    }

202 203 204 205 206 207 208 209 210 211 212
    # read lines until we have no open comments
    while (m@/\*([^*]|\*(?!/))*$@) {
	my $new;
	defined ($new = <>) || die "Unmatched comment in $ARGV";
	$_ .= $new;
    }
    # strip comments w/o options
    s@/\*(?!<)
       ([^*]+|\*(?!/))*
       \*/@@gx;

Manish Singh's avatar
Manish Singh committed
213 214 215 216
    if (m@^\s*typedef\s+enum\s*
	   ({)?\s*
	   (?:/\*<
	     (([^*]|\*(?!/))*)
217
	    >\s*\*/)?
Manish Singh's avatar
Manish Singh committed
218 219 220
         @x) {
        if (defined $2) {
            my %options = parse_options($2);
221
	    next if defined $options{"pdb-skip"};
Manish Singh's avatar
Manish Singh committed
222
	}	    
223 224 225 226 227 228 229 230 231
	# Didn't have trailing '{' look on next lines
	if (!defined $1) {
	    while (<>) {
		if (s/^\s*\{//) {
		    last;
		}
	    }
	}

232
	$symbols = ""; $contig = 1; $before = -1; @mapping = ();
233 234

	# Now parse the entries
235
	&parse_entries (\*ARGV, $ARGV);
236 237 238 239 240 241 242 243 244 245 246

	$symbols =~ s/\s*$//s;
	$symbols = wrap("\t\t\t  ", "\t\t\t  " , $symbols);
	$symbols =~ s/^\s*//s;

	my $mapping = ""; $pos = 1;
	foreach (@mapping) {
	    $mapping .= $pos++ % 2 ? "$_ => " : "'$_',\n\t\t       ";
	}
	$mapping =~ s/,\n\s*$//s;

Manish Singh's avatar
Manish Singh committed
247
	$ARGV =~ s@(?:(?:..|app)/)*@@;
Manish Singh's avatar
Manish Singh committed
248

249
	$code .= <<ENTRY;
Manish Singh's avatar
Manish Singh committed
250 251
:    $enumname =>
:	{ contig => $contig,
Manish Singh's avatar
Manish Singh committed
252
:	  header => '$ARGV',
Manish Singh's avatar
Manish Singh committed
253
:	  symbols => [ qw($symbols) ],
254
:	  mapping => { $mapping }
Manish Singh's avatar
Manish Singh committed
255
:	},
256 257 258 259 260 261
ENTRY
    }
}

$code =~ s/,\n$/\n/s;

Manish Singh's avatar
Manish Singh committed
262 263
foreach ($header, $code, $footer) { s/^://mg }

264
$outfile = "$builddir/pdb/enums.pl$FILE_EXT";
Manish Singh's avatar
Manish Singh committed
265
open OUTFILE, "> $outfile";
266
print OUTFILE $header, $external, $code, $footer;
267
close OUTFILE;
268
&write_file($outfile, "$destdir/pdb");