removed \v escaping, newer perl versions don't support this, and it'S
[platform/upstream/glib.git] / gobject / glib-mkenums.in
1 #!/usr/bin/perl -w
2
3 # glib-mkenums.pl 
4 # Information about the current enumeration
5 my $flags;                      # Is enumeration a bitmask?
6 my $seenbitshift;               # Have we seen bitshift operators?
7 my $enum_prefix;                # Prefix for this enumeration
8 my $enumname;                   # Name for this enumeration
9 my $enumshort;                  # $enumname without prefix
10 my $enumindex = 0;              # Global enum counter
11 my $firstenum = 1;              # Is this the first enumeration per file?
12 my @entries;                    # [ $name, $val ] for each entry
13
14 sub parse_trigraph {
15     my $opts = shift;
16     my @opts;
17
18     for $opt (split /\s*,\s*/, $opts) {
19         $opt =~ s/^\s*//;
20         $opt =~ s/\s*$//;
21         my ($key,$val) = $opt =~ /(\w+)(?:=(.+))?/;
22         defined $val or $val = 1;
23         push @opts, $key, $val;
24     }
25     @opts;
26 }
27 sub parse_entries {
28     my $file = shift;
29     my $file_name = shift;
30     
31     while (<$file>) {
32         
33         # read lines until comment end is matched
34         while (m@/\*([^*]|\*[^/*])*\**$@x) {
35             my $new;
36             defined ($new = <>) || die "Unmatched comment in $ARGV";
37             $_ .= $new;
38         }
39         # strip comments w/o options
40         s@/\*[^<]([^*]|\*[^/*])*\**\*/@@gx;
41
42         # strip newlines
43         s/\n//;
44         
45         # skip empty lines
46         next if m@^\s*$@;
47         
48 #       print STDERR "xxx $_\n";
49         
50         # Handle include files
51         if (/^\#include\s*<([^>]*)>/ ) {
52             my $file= "../$1";
53             open NEWFILE, $file or die "Cannot open include file $file: $!\n";
54             
55             # read lines until comment end is matched
56             while (m@/\*([^*]|\*[^/*])*\**$@x) {
57                 my $new;
58                 defined ($new = <>) || die "Unmatched comment in $file_name";
59                 $_ .= $new;
60             }
61             # strip comments w/o options
62             s@/\*[^<]([^*]|\*[^/*])*\**\*/@@gx;
63         
64             if (parse_entries (\*NEWFILE, $NEWFILE)) {
65                 return 1;
66             } else {
67                 next;
68             }
69         }
70         
71         if (/^\s*\}\s*(\w+)/) {
72             $enumname = $1;
73             $enumindex++;
74             return 1;
75         }
76         
77         if (m@^\s*
78               (\w+)\s*                   # name
79               (?:=(                      # value
80                    (?:[^,/]|/(?!\*))*
81                   ))?,?\s*
82               (?:/\*<                    # options
83                 (([^*]|\*(?!/))*)
84                >\s*\*/)?,?
85               \s*$
86              @x) {
87             my ($name, $value, $options) = ($1,$2,$3);
88
89 #           print STDERR "xxx \"$name\" \"$value\" \"$otions\"\n";
90
91             if (!defined $flags && defined $value && $value =~ /<</) {
92                 $seenbitshift = 1;
93             }
94
95             if (defined $options) {
96                 my %options = parse_trigraph($options);
97                 if (!defined $options{skip}) {
98                     push @entries, [ $name, $options{nick} ];
99                 }
100             } else {
101                 push @entries, [ $name ];
102             }
103         } elsif (m@^\s*\#@) {
104             # ignore preprocessor directives
105         } else {
106             print STDERR "$0: $file_name:$.: Failed to parse `$_'\n";
107         }
108     }
109
110     return 0;
111 }
112
113 sub version {
114     print STDERR "glib-mkenums version glib-2.0\n";   # FIXME: autogen version?
115     print STDERR "glib-mkenums comes with ABSOLUTELY NO WARRANTY.\n";
116     print STDERR "You may redistribute copies of glib-mkenums under the terms of\n";
117     print STDERR "the GNU General Public License which can be found in the\n";
118     print STDERR "GLib source package. Sources, examples and contact\n";
119     print STDERR "information are available at http://www.gtk.org\n";
120     exit 0;
121 }
122 sub usage {
123     print STDERR "Usage: glib-mkenums [options] [files...]\n";
124     print STDERR "  --fhead <text>             output file header\n";
125     print STDERR "  --fprod <text>             per input file production\n";
126     print STDERR "  --ftail <text>             output file trailer\n";
127     print STDERR "  --eprod <text>             per enum text (produced prior to value itarations)\n";
128     print STDERR "  --vhead <text>             value header, produced before iterating over enum values\n";
129     print STDERR "  --vprod <text>             value text, produced for each enum value\n";
130     print STDERR "  --vtail <text>             value tail, produced after iterating over enum values\n";
131     print STDERR "  --comments <text>          comment structure\n";
132     print STDERR "  -h, --help                 show this help message\n";
133     print STDERR "  -v, --version              print version informations\n";
134     print STDERR "Production text substitutions:\n";
135     print STDERR "  \@EnumName\@                 PrefixTheXEnum\n";
136     print STDERR "  \@enum_name\@                prefix_the_xenum\n";
137     print STDERR "  \@ENUMNAME\@                 PREFIX_THE_XENUM\n";
138     print STDERR "  \@ENUMSHORT\@                THE_XENUM\n";
139     print STDERR "  \@VALUENAME\@                PREFIX_THE_XVALUE\n";
140     print STDERR "  \@valuenick\@                the-xvalue\n";
141     print STDERR "  \@type\@                     either enum or flags\n";
142     print STDERR "  \@Type\@                     either Enum or Flags\n";
143     print STDERR "  \@TYPE\@                     either ENUM or FLAGS\n";
144     print STDERR "  \@filename\@                 name of current input file\n";
145     exit 0;
146 }
147
148 # production variables:
149 my $fhead = "";   # output file header
150 my $fprod = "";   # per input file production
151 my $ftail = "";   # output file trailer
152 my $eprod = "";   # per enum text (produced prior to value itarations)
153 my $vhead = "";   # value header, produced before iterating over enum values
154 my $vprod = "";   # value text, produced for each enum value
155 my $vtail = "";   # value tail, produced after iterating over enum values
156 # other options
157 my $comment_tmpl = "/* \@comment\@ */";
158
159 if (!defined $ARGV[0]) {
160     usage;
161 }
162 while ($_ = $ARGV[0], /^-/) {
163     shift;
164     last if /^--$/;
165     if    (/^--fhead$/)              { $fhead = $fhead . shift }
166     elsif (/^--fprod$/)              { $fprod = $fprod . shift }
167     elsif (/^--ftail$/)              { $ftail = $ftail . shift }
168     elsif (/^--eprod$/)              { $eprod = $eprod . shift }
169     elsif (/^--vhead$/)              { $vhead = $vhead . shift }
170     elsif (/^--vprod$/)              { $vprod = $vprod . shift }
171     elsif (/^--vtail$/)              { $vtail = $vtail . shift }
172     elsif (/^--comments$/)           { $comment_tmpl = shift }
173     elsif (/^--help$/ || /^-h$/)     { usage; }
174     elsif (/^--version$/ || /^-v$/)  { version; }
175     else { usage; }
176 }
177
178 # put auto-generation comment
179 {
180     my $comment = $comment_tmpl;
181     $comment =~ s/\@comment\@/Generated data (by glib-mkenums)/;
182     print "\n" . $comment . "\n\n";
183 }
184
185 if (length($fhead)) {
186     my $prod = $fhead;
187
188     $prod =~ s/\@filename\@/$ARGV/g;
189     $prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
190     $prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
191                 
192     print "$prod\n";
193 }
194
195 while (<>) {
196     if (eof) {
197         close (ARGV);           # reset line numbering
198         $firstenum = 1;         # Flag to print filename at next enum
199     }
200
201     # read lines until comment end is matched
202     while (m@/\*([^*]|\*[^/*])*\**$@x) {
203         my $new;
204         defined ($new = <>) || die "Unmatched comment in $ARGV";
205         $_ .= $new;
206     }
207     # strip comments w/o options
208     s@/\*[^<]([^*]|\*[^/*])*\**\*/@@gx;
209
210 #    print STDERR "xxx $_\n";
211
212     if (m@^\s*typedef\s+enum\s*
213            ({)?\s*
214            (?:/\*<
215              (([^*]|\*(?!/))*)
216             >\s*\*/)?
217          @x) {
218         if (defined $2) {
219             my %options = parse_trigraph ($2);
220             next if defined $options{skip};
221             $enum_prefix = $options{prefix};
222             $flags = $options{flags};
223         } else {
224             $enum_prefix = undef;
225             $flags = undef;
226         }
227         # Didn't have trailing '{' look on next lines
228         if (!defined $1) {
229             while (<>) {
230                 if (s/^\s*\{//) {
231                     last;
232                 }
233             }
234         }
235
236         $seenbitshift = 0;
237         @entries = ();
238
239         # Now parse the entries
240         parse_entries (\*ARGV, $ARGV);
241
242         # figure out if this was a flags or enums enumeration
243         if (!defined $flags) {
244             $flags = $seenbitshift;
245         }
246
247         # Autogenerate a prefix
248         if (!defined $enum_prefix) {
249             for (@entries) {
250                 my $nick = $_->[1];
251                 if (!defined $nick) {
252                     my $name = $_->[0];
253                     if (defined $enum_prefix) {
254                         my $tmp = ~ ($name ^ $enum_prefix);
255                         ($tmp) = $tmp =~ /(^\xff*)/;
256                         $enum_prefix = $enum_prefix & $tmp;
257                     } else {
258                         $enum_prefix = $name;
259                     }
260                 }
261             }
262             if (!defined $enum_prefix) {
263                 $enum_prefix = "";
264             } else {
265                 # Trim so that it ends in an underscore
266                 $enum_prefix =~ s/_[^_]*$/_/;
267             }
268         } else {
269             # canonicalize user defined prefixes
270             $enum_prefix = uc($enum_prefix);
271             $enum_prefix =~ s/-/_/g;
272             $enum_prefix =~ s/(.*)([^_])$/$1$2_/;
273         }
274         
275         for $entry (@entries) {
276             my ($name,$nick) = @{$entry};
277             if (!defined $nick) {
278                 ($nick = $name) =~ s/^$enum_prefix//;
279                 $nick =~ tr/_/-/;
280                 $nick = lc($nick);
281                 @{$entry} = ($name, $nick);
282             }
283         }
284         
285
286         # Spit out the output
287         
288         # enumname is e.g. GMatchType
289         $enspace = $enumname;
290         $enspace =~ s/^([A-Z][a-z]*).*$/$1/;
291         
292         $enumshort = $enumname;
293         $enumshort =~ s/^[A-Z][a-z]*//;
294         $enumshort =~ s/([^A-Z])([A-Z])/$1_$2/g;
295         $enumshort =~ s/([A-Z][A-Z])([A-Z][0-9a-z])/$1_$2/g;
296         $enumshort = uc($enumshort);
297
298         $enumlong = uc($enspace) . "_" . $enumshort;
299         $enumsym = lc($enspace) . "_" . lc($enumshort);
300
301         if ($firstenum) {
302             $firstenum = 0;
303             
304             if (length($fprod)) {
305                 my $prod = $fprod;
306
307                 $prod =~ s/\@filename\@/$ARGV/g;
308                 $prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
309                 $prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
310                 
311                 print "$prod\n";
312             }
313         }
314         
315         if (length($eprod)) {
316             my $prod = $eprod;
317
318             $prod =~ s/\@enum_name\@/$enumsym/g;
319             $prod =~ s/\@EnumName\@/$enumname/g;
320             $prod =~ s/\@ENUMSHORT\@/$enumshort/g;
321             $prod =~ s/\@ENUMNAME\@/$enumlong/g;
322             if ($flags) { $prod =~ s/\@type\@/flags/g; } else { $prod =~ s/\@type\@/enum/g; }
323             if ($flags) { $prod =~ s/\@Type\@/Flags/g; } else { $prod =~ s/\@Type\@/Enum/g; }
324             if ($flags) { $prod =~ s/\@TYPE\@/FLAGS/g; } else { $prod =~ s/\@TYPE\@/ENUM/g; }
325             $prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
326             $prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
327
328             print "$prod\n";
329         }
330
331         if (length($vhead)) {
332             my $prod = $vhead;
333
334             $prod =~ s/\@enum_name\@/$enumsym/g;
335             $prod =~ s/\@EnumName\@/$enumname/g;
336             $prod =~ s/\@ENUMSHORT\@/$enumshort/g;
337             $prod =~ s/\@ENUMNAME\@/$enumlong/g;
338             if ($flags) { $prod =~ s/\@type\@/flags/g; } else { $prod =~ s/\@type\@/enum/g; }
339             if ($flags) { $prod =~ s/\@Type\@/Flags/g; } else { $prod =~ s/\@Type\@/Enum/g; }
340             if ($flags) { $prod =~ s/\@TYPE\@/FLAGS/g; } else { $prod =~ s/\@TYPE\@/ENUM/g; }
341             $prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
342             $prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
343             
344             print "$prod\n";
345         }
346
347         if (length($vprod)) {
348             my $prod = $vprod;
349             
350             $prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
351             $prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
352             for (@entries) {
353                 my ($name,$nick) = @{$_};
354                 my $tmp_prod = $vprod;
355
356                 $tmp_prod =~ s/\@VALUENAME\@/$name/g;
357                 $tmp_prod =~ s/\@valuenick\@/$nick/g;
358                 if ($flags) { $tmp_prod =~ s/\@type\@/flags/g; } else { $tmp_prod =~ s/\@type\@/enum/g; }
359                 if ($flags) { $tmp_prod =~ s/\@Type\@/Flags/g; } else { $tmp_prod =~ s/\@Type\@/Enum/g; }
360                 if ($flags) { $tmp_prod =~ s/\@TYPE\@/FLAGS/g; } else { $tmp_prod =~ s/\@TYPE\@/ENUM/g; }
361
362                 print "$tmp_prod\n";
363             }
364         }
365
366         if (length($vtail)) {
367             my $prod = $vtail;
368
369             $prod =~ s/\@enum_name\@/$enumsym/g;
370             $prod =~ s/\@EnumName\@/$enumname/g;
371             $prod =~ s/\@ENUMSHORT\@/$enumshort/g;
372             $prod =~ s/\@ENUMNAME\@/$enumlong/g;
373             if ($flags) { $prod =~ s/\@type\@/flags/g; } else { $prod =~ s/\@type\@/enum/g; }
374             if ($flags) { $prod =~ s/\@Type\@/Flags/g; } else { $prod =~ s/\@Type\@/Enum/g; }
375             if ($flags) { $prod =~ s/\@TYPE\@/FLAGS/g; } else { $prod =~ s/\@TYPE\@/ENUM/g; }
376             $prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
377             $prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
378             
379             print "$prod\n";
380         }
381     }
382 }
383
384 if (length($ftail)) {
385     my $prod = $ftail;
386
387     $prod =~ s/\@filename\@/$ARGV/g;
388     $prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
389     $prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
390                 
391     print "$prod\n";
392 }
393
394 # put auto-generation comment
395 {
396     my $comment = $comment_tmpl;
397     $comment =~ s/\@comment\@/Generated data ends here/;
398     print "\n" . $comment . "\n\n";
399 }