Gimp/pdb/pdbgen.pl
Jehan 15ec254148 Issue #5946: skip gimp_*get_*() API from GObject Introspection.
The get() API are sometimes nicer in C code because it's just simpler to
loop through C arrays, but they end up with similar API to the list()
variants for binding, or with a useless size return value (since most
higher level languages have length-aware array types, which is what
GList are transformed into).

So let's use the list() variants as the main ones and skip the get()
variants. I hesitated to rename the list() variants to get() with
`(rename-to)` annotations but since I am unsure if the get() bindings
are absolutely useless, I don't think it's the best idea. Maybe on some
other language usable as GI binding, the get() variant might be
different again and nicer to use. So if we shadowed these by renaming
list() ones, the day we change our mind, we'd have to rename get() ones
too (which would be very confusing), or else break bindings' API. To
avoid this, I just skip the get() ones altogether in bindings but leave
their name available in the bindings.
2022-06-27 21:20:06 +02:00

242 lines
6.1 KiB
Perl
Executable file

#!/usr/bin/perl -w
# GIMP - The GNU Image Manipulation Program
# Copyright (C) 1998-2003 Manish Singh <yosh@gimp.org>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT 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
# along with this program. If not, see <https://www.gnu.org/licenses/>.
require 5.004;
BEGIN {
$srcdir = $ENV{srcdir} || '.';
$destdir = $ENV{destdir} || '.';
$builddir = $ENV{builddir} || '.';
}
use lib $srcdir;
BEGIN {
# Some important stuff
require 'pdb.pl';
require 'enums.pl';
require 'util.pl';
# What to do?
require 'groups.pl';
if ($ENV{PDBGEN_GROUPS}) {
@groups = split(/:/, $ENV{PDBGEN_GROUPS});
}
}
# Stifle "used only once" warnings
$destdir = $destdir;
$builddir = $builddir;
%pdb = ();
# The actual parser (in a string so we can eval it in another namespace)
$evalcode = <<'CODE';
{
my $file = $main::file;
my $srcdir = $main::srcdir;
my $copyvars = sub {
my $dest = shift;
foreach (@_) {
if (eval "defined scalar $_") {
(my $var = $_) =~ s/^(\W)//;
for ($1) {
/\$/ && do { $$dest->{$var} = $$var ; last; };
/\@/ && do { $$dest->{$var} = [ @$var ]; last; };
/\%/ && do { $$dest->{$var} = { %$var }; last; };
}
}
}
};
# Variables to evaluate and insert into the PDB structure
my @procvars = qw($name $group $blurb $help $author $copyright $date $since
$deprecated @inargs @outargs %invoke $canonical_name
$lib_private $skip_gi);
# These are attached to the group structure
my @groupvars = qw($desc $doc_title $doc_short_desc $doc_long_desc
$lib_private $skip_gi
@headers %extra);
# Hook some variables into the top-level namespace
*pdb = \%main::pdb;
*gen = \%main::gen;
*grp = \%main::grp;
# Hide our globals
my $safeeval = sub { local(%pdb, %gen, %grp); eval $_[0]; die $@ if $@ };
# Some standard shortcuts used by all def files
&$safeeval("do '$main::srcdir/stddefs.pdb'");
# Group properties
foreach (@groupvars) { eval "undef $_" }
# Load the file in and get the group info
&$safeeval("require '$main::srcdir/groups/$file.pdb'");
# Save these for later
&$copyvars(\$grp{$file}, @groupvars);
foreach $proc (@procs) {
# Reset all our PDB vars so previous defs don't interfere
foreach (@procvars) { eval "undef $_" }
# Get the info
&$safeeval("&$proc");
# Some derived fields
$name = $proc;
$group = $file;
($canonical_name = $name) =~ s/_/-/g;
# Load the info into %pdb, making copies of the data instead of refs
my $entry = {};
&$copyvars(\$entry, @procvars);
$pdb{$proc} = $entry;
}
# Find out what to do with these entries
while (my ($dest, $procs) = each %exports) { push @{$gen{$dest}}, @$procs }
}
CODE
# Slurp in the PDB defs
foreach $file (@groups) {
print "Processing $srcdir/groups/$file.pdb...\n";
eval "package Gimp::CodeGen::Safe::$file; $evalcode;";
die $@ if $@;
}
# Squash whitespace into just single spaces between words.
# Single new lines are considered as normal spaces, but n > 1 newlines are considered (n - 1) newlines.
# The slightly complicated suite of regexp is so that \n\s+\n is still considered a double newline.
sub trimspace { for (${$_[0]}) { s/(\S)[\ \t\r\f]*\n[\ \t\r\f]*(\S)/$1 $2/g; s/[\ \t\r\f]+/ /gs;
s/\n(([\ \t\r\f]*\n)+)/$1/g; s/[\ \t\r\f]*\n[\ \t\r\f]/\n/g ; s/^\s+//; s/\s+$//; } }
# Trim spaces and escape quotes C-style
sub nicetext {
my $val = shift;
if (defined $$val) {
&trimspace($val);
$$val =~ s/"/\\"/g;
}
}
# Do the same for all the strings in the args, plus expand constraint text
sub niceargs {
my $args = shift;
foreach $arg (@$args) {
foreach (keys %$arg) {
&nicetext(\$arg->{$_});
}
}
}
# Trim spaces from all the elements in a list
sub nicelist {
my $list = shift;
foreach (@$list) { &trimspace(\$_) }
}
# Add args for array lengths
sub arrayexpand {
my $args = shift;
my $newargs;
foreach (@$$args) {
if (exists $_->{array}) {
my $arg = $_->{array};
$arg->{name} = 'num_' . $_->{name} unless exists $arg->{name};
# We can't have negative lengths, but let them set a min number
unless (exists $arg->{type}) {
$arg->{type} = '0 <= int32';
}
elsif ($arg->{type} !~ /^\s*\d+\s*</) {
$arg->{type} = '0 <= ' . $arg->{type};
}
$arg->{void_ret} = 1 if exists $_->{void_ret};
$arg->{num} = 1;
push @$newargs, $arg;
}
push @$newargs, $_;
}
$$args = $newargs;
}
sub canonicalargs {
my $args = shift;
foreach $arg (@$args) {
($arg->{canonical_name} = $arg->{name}) =~ s/_/-/g;
}
}
# Post-process each pdb entry
while ((undef, $entry) = each %pdb) {
&nicetext(\$entry->{blurb});
&nicetext(\$entry->{help});
&nicetext(\$entry->{author});
&nicetext(\$entry->{copyright});
&nicetext(\$entry->{date});
foreach (qw(in out)) {
my $args = $_ . 'args';
if (exists $entry->{$args}) {
&arrayexpand(\$entry->{$args});
&niceargs($entry->{$args});
&canonicalargs($entry->{$args});
}
}
&nicelist($entry->{invoke}{headers}) if exists $entry->{invoke}{headers};
&nicelist($entry->{globals}) if exists $entry->{globals};
$entry->{invoke}{success} = 'TRUE' unless exists $entry->{invoke}{success};
}
# Generate code from the modules
my $didstuff;
while (@ARGV) {
my $type = shift @ARGV;
print "\nProcessing $type...\n";
if (exists $gen{$type}) {
require "$type.pl";
&{"Gimp::CodeGen::${type}::generate"}($gen{$type});
print "done.\n";
$didstuff = 1;
}
else {
print "nothing to do.\n";
}
}
print "\nNothing done at all.\n" unless $didstuff;