# 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/>.
package Gimp::CodeGen::lib;
# Generates all the libgimp C wrappers (used by plugins)
$destdir =
"$main::destdir/libgimp";
$builddir =
"$main::builddir/libgimp";
*arg_types = \%Gimp::CodeGen::pdb::arg_types;
*arg_parse = \&Gimp::CodeGen::pdb::arg_parse;
*enums = \%Gimp::CodeGen::enums::enums;
*write_file = \&Gimp::CodeGen::util::write_file;
*FILE_EXT = \$Gimp::CodeGen::util::FILE_EXT;
use Text::Wrap qw(wrap);
sub desc_wrap {
my ($str) = @_;
my $leading =
' * ';
my $wrapped;
$str =~ s/\s+$//;
# trim trailing whitespace
$str =~ s/&/&\;/g;
$str =~ s/\</<\;/g;
$str =~ s/\>/>\;/g;
$Text::Wrap::columns =
72;
$wrapped = wrap($leading, $leading, $str);
$wrapped =~ s/[ \t]+\n/\n/g;
return $wrapped;
}
sub generate_fun {
my ($proc, $out) = @_;
my @inargs = @{$proc->{inargs}}
if (defined $proc->{inargs});
my @outargs = @{$proc->{outargs}}
if (defined $proc->{outargs});
sub libtype {
my $arg = shift;
my $outarg = shift;
my ($type, $name) = &arg_parse($arg->{type});
my $argtype = $arg_types{$type};
my $rettype =
'';
if ($type eq
'enum') {
return
"$name ";
}
if ($outarg) {
$rettype .= $argtype->{type};
}
else {
if (exists $argtype->{struct}) {
$rettype .=
'const ';
}
$rettype .= $argtype->{const_type};
}
$rettype =~ s/int32/int/ unless exists $arg->{keep_size};
$rettype .=
'*' if exists $argtype->{struct};
return $rettype;
}
my $funcname =
"gimp_$name";
my $wrapped =
"";
my $new_funcname = $funcname;
my %usednames;
my $retdesc =
" * Returns:";
my $func_annotations =
"";
if ($proc->{lib_private}) {
$wrapped =
'_';
}
$skip_gi =
'';
if ($proc->{skip_gi}) {
$skip_gi =
' (skip)';
}
if ($proc->{deprecated}) {
if ($proc->{deprecated} eq
'NONE') {
push @{$out->{protos}},
"GIMP_DEPRECATED\n";
}
else {
my $underscores = $proc->{deprecated};
$underscores =~ s/-/_/g;
push @{$out->{protos}},
"GIMP_DEPRECATED_FOR($underscores)\n";
}
}
# Find the return argument (defaults to the first arg if not
# explicitly set
my $retarg = undef;
my $retarg_len = undef;
$retvoid =
0;
foreach (@outargs) {
$retarg = $_, last
if exists $_->{retval};
}
unless ($retarg) {
if (scalar @outargs) {
if (exists $outargs[
0]->{void_ret}) {
$retvoid =
1;
}
else {
$retarg = exists $outargs[
0]->{num} ? $outargs[
1]
: $outargs[
0];
}
}
}
my $rettype;
if ($retarg) {
my ($type) = &arg_parse($retarg->{type});
my $argtype = $arg_types{$type};
my $annotate =
"";
$rettype = &libtype($retarg,
1);
chop $rettype unless $rettype =~ /\*$/;
$retarg->{retval} =
1;
if (exists $argtype->{array}) {
$retarg_len = $retarg->{array}->{name};
$annotate =
" (array length=$retarg_len)";
}
if (exists $retarg->{none_ok} && $type ne
'sample_point' && $type ne
'guide') {
$annotate .=
" (nullable)";
}
if (exists $argtype->{out_annotate}) {
$annotate .=
" $argtype->{out_annotate}";
}
if ($annotate eq
"") {
$retdesc .=
" $retarg->{desc}";
}
else {
if (exists $retarg->{desc}) {
if ((length ($annotate) +
length ($retarg->{desc})) >
65) {
$retdesc .= $annotate .
":\n * " . $retarg->{desc};
}
else {
$retdesc .= $annotate .
": " . $retarg->{desc};
}
}
}
unless ($retdesc =~ /[\.\!\?]$/) { $retdesc .=
'.' }
my $array_test = $retarg->{type};
$array_test =~ s/array$//g;
if ($retarg->{type} eq
'colorarray') {
$retdesc .=
"\n * The returned value must be freed with gimp_color_array_free().";
}
elsif ($retarg->{type} eq
'strv') {
$retdesc .=
"\n * The returned value must be freed with g_strfreev().";
}
elsif ($retarg->{type} eq
'param') {
$retdesc .=
"\n * The returned value must be freed with g_param_spec_unref().";
}
elsif ($retarg->{type} eq
'string' || $retarg->{type} ne $array_test) {
$retdesc .=
"\n * The returned value must be freed with g_free().";
}
}
else {
# No return values
$rettype =
'void';
}
# The parameters to the function
my $arglist =
"";
my $argdesc =
"";
my $sincedesc =
"";
my $inargs_testing =
"";
my $value_array =
"";
my $arg_array =
"";
my $argc =
0;
foreach (@inargs) {
my ($type, @typeinfo) = &arg_parse($_->{type});
my $arg = $arg_types{$type};
my $var = $_->{name};
my $desc = exists $_->{desc} ? $_->{desc} :
"";
my $var_len;
my $value;
my $n_annotations =
0;
if (exists $_->{nopdb}) {
$argc--;
if (defined $typeinfo[
0]) {
$min = ($typeinfo[
1] eq
'<') ? ($typeinfo[
0] +
1) : $typeinfo[
0];
# gsize is positive, no need to test for >= 0.
if ($min >
0) {
if ($rettype eq
'void') {
# void rettype is in fact boolean.
$inargs_testing .=
"\n" .
' ' x
2 .
"g_return_val_if_fail ($_->{name} >= $min, FALSE);";
}
else {
# TODO: I should in fact test the exact return
# type. E.g. it could be int or float. But since
# we have no such case (while also generating in
# argument testing) so far, I took the easy way
# out. To be completed if needed.
$inargs_testing .=
"\n" .
' ' x
2 .
"g_return_val_if_fail ($_->{name} >= $min, NULL);";
}
}
}
if (defined $typeinfo[
2]) {
$max = ($typeinfo[
3] eq
'<') ? ($typeinfo[
2] -
1) : $typeinfo[
2];
if ($rettype eq
'void') {
$inargs_testing .=
"\n" .
' ' x
2 .
"g_return_val_if_fail ($_->{name} <= $max, FALSE);";
}
else {
$inargs_testing .=
"\n" .
' ' x
2 .
"g_return_val_if_fail ($_->{name} <= $max, NULL);";
}
}
}
else {
# This gets passed to gimp_value_array_new_with_types()
if ($type eq
'enum') {
$enum_type = $typeinfo[
0];
$enum_type =~ s/([a-z])([A-Z])/$
1_$
2/g;
$enum_type =~ s/([A-Z]+)([A-Z])/$
1_$
2/g;
$enum_type =~ tr/[a-z]/[A-Z]/;
$enum_type =~ s/^GIMP/GIMP_TYPE/;
$enum_type =~ s/^GEGL/GEGL_TYPE/;
$value_array .=
"$enum_type, ";
}
else {
$value_array .=
"$arg->{gtype}, ";
}
if (exists $_->{array}) {
$value_array .=
"NULL";
}
else {
$value_array .=
"$var";
}
$value_array .=
",\n" .
" " x
42;
}
if (exists $_->{array}) {
my $arrayarg = $_->{array};
$value =
"gimp_value_array_index (args, $argc)";
if (exists $arrayarg->{name}) {
$var_len = $arrayarg->{name};
}
else {
$var_len =
'num_' . $_->{name};
}
# This is the list of g_value_set_foo_array
$arg_array .=
eval qq/
" $arg->{set_value_func};\n"/;
}
$usednames{$_->{name}}++;
$arglist .= &libtype($_,
0);
$arglist .= $_->{name};
$arglist .=
', ';
$argdesc .=
" * \@$_->{name}";
$argdesc .=
":";
if (exists $arg->{array}) {
$argdesc .=
" (array length=$var_len)";
$n_annotations++;
}
if (exists $arg->{in_annotate}) {
$argdesc .=
" $arg->{in_annotate}";
$n_annotations++;
}
if (exists $_->{none_ok} && $type ne
'sample_point' && $type ne
'guide') {
$argdesc .=
" (nullable)";
$n_annotations++;
}
if ($n_annotations >
0) {
$argdesc .=
":";
}
$argdesc .=
" $desc";
unless ($argdesc =~ /[\.\!\?]$/) { $argdesc .=
'.' }
$argdesc .=
"\n";
$argc++;
}
if ($inargs_testing ne
"") {
$inargs_testing .=
"\n";
}
# This marshals the return value(s)
my $return_args =
"";
my $return_marshal =
"gimp_value_array_unref (return_vals);";
# return success/failure boolean if we don't have anything else
if ($rettype eq
'void') {
$return_args .=
"\n" .
' ' x
2 .
"gboolean success = TRUE;";
$retdesc .=
" TRUE on success.";
}
# We only need to bother with this if we have to return a value
if ($rettype ne
'void' || $retvoid) {
my $once =
0;
my $firstvar;
my @initnums;
foreach (@outargs) {
my ($type) = &arg_parse($_->{type});
my $arg = $arg_types{$type};
my $var;
$return_marshal =
"" unless $once++;
$_->{libname} = exists $usednames{$_->{name}} ?
"ret_$_->{name}"
: $_->{name};
if (exists $_->{num}) {
if (!exists $_->{no_lib}) {
push @initnums, $_;
}
}
elsif (exists $_->{retval}) {
$return_args .=
"\n" .
' ' x
2;
$return_args .= &libtype($_,
1);
# The return value variable
$var = $_->{libname};
$return_args .= $var;
# Save the first var to "return" it
$firstvar = $var unless defined $firstvar;
if ($_->{libdef}) {
$return_args .=
" = $_->{libdef}";
}
else {
$return_args .=
" = $arg->{init_value}";
}
$return_args .=
";";
if (exists $_->{array} && exists $_->{array}->{no_lib}) {
$return_args .=
"\n" .
' ' x
2 .
"gint num_$var;";
}
}
elsif ($retvoid) {
push @initnums, $_ unless exists $arg->{struct};
}
}
if (scalar(@initnums)) {
foreach (@initnums) {
$return_marshal .=
"\*$_->{libname} = ";
my ($type) = &arg_parse($_->{type});
for ($arg_types{$type}->{type}) {
/\*$/ &&
do { $return_marshal .=
"NULL"; last };
/boolean/ &&
do { $return_marshal .=
"FALSE"; last };
/double/ &&
do { $return_marshal .=
"0.0"; last };
$return_marshal .=
"0";
}
$return_marshal .=
";\n ";
}
$return_marshal =~ s/\n $/\n\n /s;
}
if ($rettype eq
'void') {
$return_marshal .= <<CODE;
success = GIMP_VALUES_GET_ENUM (return_vals,
0) == GIMP_PDB_SUCCESS;
if (success)
CODE
}
else {
$return_marshal .= <<CODE;
if (GIMP_VALUES_GET_ENUM (return_vals,
0) == GIMP_PDB_SUCCESS)
CODE
}
$return_marshal .=
' ' x
4 .
"{\n" if $
#outargs;
my $argc =
1; my ($numpos, $numtype);
foreach (@outargs) {
my ($type) = &arg_parse($_->{type});
my $desc = exists $_->{desc} ? $_->{desc} :
"";
my $arg = $arg_types{$type};
my $var;
# The return value variable
$var =
"";
$var_len = $retarg_len;
unless (exists $_->{retval}) {
$var .=
'*';
$arglist .= &libtype($_,
1);
$arglist .=
'*' unless exists $arg->{struct};
$arglist .=
"$_->{libname}";
$arglist .=
', ';
$argdesc .=
" * \@$_->{libname}";
if ($arg->{name} eq
'COLOR') {
$argdesc .=
": (out caller-allocates)";
}
else {
$argdesc .=
": (out)";
}
if (exists $arg->{array}) {
my $arrayarg = $_->{array};
if (exists $arrayarg->{name}) {
$var_len = $arrayarg->{name};
}
else {
$var_len =
'num_' . $_->{libname};
}
$argdesc .=
" (array length=$var_len)";
}
if (exists $arg->{out_annotate}) {
$argdesc .=
" $arg->{out_annotate}";
}
$argdesc .=
": $desc";
}
$var = exists $_->{retval} ?
"" :
'*';
$var .= $_->{libname};
if (exists $_->{nopdb}) {
$argc--;
}
$value =
"return_vals, $argc";
if (! exists $_->{nopdb}) {
$return_marshal .=
' ' x
2 if $
#outargs;
$return_marshal .=
eval qq/
" $arg->{dup_value_func};\n"/;
}
if ($argdesc) {
unless ($argdesc =~ /[\.\!\?]$/) { $argdesc .=
'.' }
unless ($argdesc =~ /\n$/) { $argdesc .=
"\n" }
}
$argc++;
}
$return_marshal .=
' ' x
4 .
"}\n" if $
#outargs;
$return_marshal .= <<
'CODE';
gimp_value_array_unref (return_vals);
CODE
unless ($retvoid) {
$return_marshal .=
' ' x
2 .
"return $firstvar;";
}
else {
$return_marshal .=
' ' x
2 .
"return success;";
}
}
else {
$return_marshal = <<CODE;
success = GIMP_VALUES_GET_ENUM (return_vals,
0) == GIMP_PDB_SUCCESS;
$return_marshal
return success;
CODE
chop $return_marshal;
}
if ($arglist) {
my @arglist = split(/, /, $arglist);
my $longest =
0; my $seen =
0;
foreach (@arglist) {
/(const \w+) \S+/ || /(\w+) \S+/;
my $len = length($
1);
my $num = scalar @{[ /\*/g ]};
$seen = $num
if $seen < $num;
$longest = $len
if $longest < $len;
}
$longest += $seen;
my $once =
0; $arglist =
"";
foreach (@arglist) {
my $space = rindex($_,
' ');
my $len = $longest - $space +
1;
$len -= scalar @{[ /\*/g ]};
substr($_, $space,
1) =
' ' x $len
if $space != -
1 && $len >
1;
$arglist .=
"\t" if $once;
$arglist .= $_;
$arglist .=
",\n";
$once++;
}
$arglist =~ s/,\n$//;
}
else {
$arglist =
"void";
}
$rettype =
'gboolean' if $rettype eq
'void';
# Our function prototype for the headers
(my $hrettype = $rettype) =~ s/ //g;
my $proto =
"$hrettype $wrapped$funcname ($arglist);\n";
$proto =~ s/ +/ /g;
push @{$out->{protos}}, $proto;
my $clist = $arglist;
my $padlen = length($wrapped) + length($funcname) +
2;
my $padding =
' ' x $padlen;
$clist =~ s/\t/$padding/eg;
if ($proc->{since}) {
$sincedesc =
"\n *\n * Since: $proc->{since}";
}
my $procdesc =
'';
if ($proc->{deprecated}) {
if (! $proc->{deprecated_since}) {
die
"ERROR: missing 'deprecated_since' variable on $name.\n";
}
$deprecated_since = $proc->{deprecated_since};
if ($proc->{deprecated} eq
'NONE') {
if ($proc->{blurb}) {
$procdesc = &desc_wrap($proc->{blurb}) .
"\n *\n";
}
if ($proc->{help}) {
$procdesc .= &desc_wrap($proc->{help}) .
"\n *\n";
}
$procdesc .= &desc_wrap(
"Deprecated: $deprecated_since: There is no replacement " .
"for this procedure.");
}
else {
my $replacement = $proc->{deprecated};
chomp $replacement;
if ($replacement =~ / /) {
# Use the deprecated string as-is.
#$replacement =~ s/"/\\"/g;
}
elsif ($replacement =~ /:/) {
# Replacement is a GEGL operation.
$replacement =
"filter \"$replacement\
"";
}
else {
# Replacement is another function.
$replacement =~ s/-/_/g;
$replacement .=
'()';
}
if ($proc->{blurb}) {
$procdesc = &desc_wrap($proc->{blurb}) .
"\n *\n";
}
if ($proc->{help}) {
$procdesc .= &desc_wrap($proc->{help}) .
"\n *\n";
}
$procdesc .= &desc_wrap(
"Deprecated: $deprecated_since: " .
"Use $replacement instead.");
}
}
else {
$procdesc = &desc_wrap($proc->{blurb}) .
"\n *\n" .
&desc_wrap($proc->{help});
}
return <<CODE;
/**
* $wrapped$funcname:$func_annotations$skip_gi
$argdesc *
$procdesc
*
$retdesc$sincedesc
**/
$rettype
$wrapped$funcname ($clist)
{
GimpValueArray *args;
GimpValueArray *return_vals;$return_args
$inargs_testing
args = gimp_value_array_new_from_types (NULL,
${value_array}G_TYPE_NONE);
$arg_array
return_vals = _gimp_pdb_run_procedure_array (gimp_get_pdb (),
"gimp-$proc->{canonical_name}",
args);
gimp_value_array_unref (args);
$return_marshal
}
CODE
}
sub generate_hbody {
my ($out, $extra) = @_;
if (exists $extra->{protos}) {
my $proto =
"";
foreach (split(/\n/, $extra->{protos})) {
next
if /^\s*$/;
if (/^\t/ && length($proto)) {
s/\s+/ /g; s/ $//; s/^ /\t/;
$proto .= $_ .
"\n";
}
else {
push @{$out->{protos}}, $proto
if length($proto);
s/\s+/ /g; s/^ //; s/ $//;
$proto = $_ .
"\n";
}
}
}
my @longest = (
0,
0,
0); my @arglist = (); my $seen =
0;
foreach (@{$out->{protos}}) {
my $arglist;
if (!/^GIMP_DEPRECATED/) {
my $len;
$arglist = [ split(
' ', $_,
3) ];
if ($arglist->[
1] =~ /^_/) {
$arglist->[
0] =
"G_GNUC_INTERNAL ".$arglist->[
0];
}
for (
0..
1) {
$len = length($arglist->[$_]);
$longest[$_] = $len
if $longest[$_] < $len;
}
foreach (split(/,/, $arglist->[
2])) {
next unless /(const \w+) \S+/ || /(\w+) \S+/;
$len = length($
1) +
1;
my $num = scalar @{[ /\*/g ]};
$seen = $num
if $seen < $num;
$longest[
2] = $len
if $longest[
2] < $len;
}
}
else {
$arglist = $_;
}
push @arglist, $arglist;
}
$longest[
2] += $seen;
@{$out->{protos}} = ();
foreach (@arglist) {
my $arg;
if (ref) {
my ($type, $func, $arglist) = @$_;
my @args = split(/,/, $arglist); $arglist =
"";
foreach (@args) {
$space = rindex($_,
' ');
if ($space >
0 && substr($_, $space -
1,
1) eq
')') {
$space = rindex($_,
' ', $space -
1)
}
my $len = $longest[
2] - $space +
1;
$len -= scalar @{[ /\*/g ]};
$len++
if /\t/;
if ($space != -
1 && $len >
1) {
substr($_, $space,
1) =
' ' x $len;
}
$arglist .= $_;
$arglist .=
"," if !/;\n$/;
}
$arg = $type;
$arg .=
' ' x ($longest[
0] - length($type) +
1) . $func;
$arg .=
' ' x ($longest[
1] - length($func) +
1) . $arglist;
$arg =~ s/\t/
' ' x ($longest[
0] + $longest[
1] +
3)/eg;
}
else {
$arg = $_;
}
push @{$out->{protos}}, $arg;
}
my $body =
'';
$body = $extra->{decls}
if exists $extra->{decls};
foreach (@{$out->{protos}}) { $body .= $_ }
if ($out->{deprecated}) {
$body .=
"#endif /* GIMP_DISABLE_DEPRECATED */\n";
}
chomp $body;
return $body;
}
sub generate {
my @procs = @{(shift)};
my %out;
foreach $name (@procs) {
my $proc = $main::pdb{$name};
my $out = \%{$out{$proc->{group}}};
my @inargs = @{$proc->{inargs}}
if (defined $proc->{inargs});
my @outargs = @{$proc->{outargs}}
if (defined $proc->{outargs});
$out->{code} .= generate_fun($proc, $out);
}
my $lgpl_top = <<
'LGPL';
/* LIBGIMP - The GIMP Library
* Copyright (C)
1995-
2003 Peter Mattis and Spencer Kimball
*
LGPL
my $lgpl_bottom = <<
'LGPL';
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version
3 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License
for more details.
*
* You should have received a
copy of the GNU Lesser General Public
* License along with this library.
If not, see
* <
https://www.gnu.org/licenses/>.
*/
/* NOTE: This file is auto-generated by pdbgen.pl */
LGPL
# We generate two files, a _pdb.h file with prototypes for all
# the functions we make, and a _pdb.c file for the actual implementation
while (my($group, $out) = each %out) {
my $hname =
"${group}pdb.h";
my $cname =
"${group}pdb.c";
if ($group ne
'gimp') {
$hname =
"gimp${hname}";
$cname =
"gimp${cname}";
}
$hname =~ s/_//g; $hname =~ s/pdb\./_pdb./;
$cname =~ s/_//g; $cname =~ s/pdb\./_pdb./;
my $hfile =
"$builddir/$hname$FILE_EXT";
my $cfile =
"$builddir/$cname$FILE_EXT";
my $body;
my $extra = {};
if (exists $main::grp{$group}->{extra}->{lib}) {
$extra = $main::grp{$group}->{extra}->{lib}
}
$body = generate_hbody($out, $extra,
"protos");
open HFILE,
"> $hfile" or die
"Can't open $hfile: $!\n";
print HFILE $lgpl_top;
print HFILE
" * $hname\n";
print HFILE $lgpl_bottom;
my $guard =
"__GIMP_\U$group\E_PDB_H__";
print HFILE <<HEADER;
#if !defined (__GIMP_H_INSIDE__) && !defined (GIMP_COMPILATION)
#error "Only <libgimp/gimp.h> can be included directly."
#endif
#ifndef $guard
#define $guard
G_BEGIN_DECLS
/*
For information look into the C source or the html documentation */
$body
G_END_DECLS
#endif /* $guard */
HEADER
close HFILE;
&write_file($hfile, $destdir);
open CFILE,
"> $cfile" or die
"Can't open $cfile: $!\n";
print CFILE $lgpl_top;
print CFILE
" * $cname\n";
print CFILE $lgpl_bottom;
print CFILE qq/
#include "config.h"\n\n/;
print CFILE qq/
#include "stamp-pdbgen.h"\n\n/;
print CFILE $out->{headers},
"\n" if exists $out->{headers};
print CFILE qq/
#include "gimp.h"\n/;
if (exists $main::grp{$group}->{lib_private}) {
print CFILE qq/
#include "$hname"\n/;
}
if (exists $main::grp{$group}->{doc_title}) {
$long_desc = &desc_wrap($main::grp{$group}->{doc_long_desc});
print CFILE <<SECTION_DOCS;
/**
* SECTION: $main::grp{$group}->{doc_title}
* \@title: $main::grp{$group}->{doc_title}
* \@short_description: $main::grp{$group}->{doc_short_desc}
*
${long_desc}
**/
SECTION_DOCS
}
print CFILE
"\n", $extra->{code}
if exists $extra->{code};
print CFILE $out->{code};
close CFILE;
&write_file($cfile, $destdir);
}
if (! $ENV{PDBGEN_GROUPS}) {
my $gimp_pdb_headers =
"$builddir/gimp_pdb_headers.h$FILE_EXT";
open PFILE,
"> $gimp_pdb_headers" or die
"Can't open $gimp_pdb_headers: $!\n";
print PFILE $lgpl_top;
print PFILE
" * gimp_pdb_headers.h\n";
print PFILE $lgpl_bottom;
my $guard =
"__GIMP_PDB_HEADERS_H__";
print PFILE <<HEADER;
#if !defined (__GIMP_H_INSIDE__) && !defined (GIMP_COMPILATION)
#error "Only <libgimp/gimp.h> can be included directly."
#endif
#ifndef $guard
#define $guard
HEADER
my @groups;
foreach $group (keys %out) {
my $hname =
"${group}pdb.h";
if ($group ne
'gimp') {
$hname =
"gimp${hname}";
}
$hname =~ s/_//g; $hname =~ s/pdb\./_pdb./;
if (! exists $main::grp{$group}->{lib_private}) {
push @groups, $hname;
}
}
foreach $group (sort @groups) {
print PFILE
"#include <libgimp/$group>\n";
}
print PFILE <<HEADER;
#endif /* $guard */
HEADER
close PFILE;
&write_file($gimp_pdb_headers, $destdir);
}
}