mirror of
https://github.com/Ryujinx/GtkSharp.git
synced 2024-12-23 17:55:27 +00:00
1284 lines
36 KiB
Perl
Executable file
1284 lines
36 KiB
Perl
Executable file
#!/usr/bin/perl
|
|
#
|
|
# gapi2xml.pl : Generates an XML representation of GObject based APIs.
|
|
#
|
|
# Author: Mike Kestner <mkestner@speakeasy.net>
|
|
#
|
|
# Copyright (c) 2001-2003 Mike Kestner
|
|
# Copyright (c) 2003-2009 Novell, Inc.
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of version 2 of the GNU General Public
|
|
# License as published by the Free Software Foundation.
|
|
#
|
|
# 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, write to the
|
|
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
# Boston, MA 02111-1307, USA.
|
|
##############################################################
|
|
|
|
$parser_version = 2;
|
|
$debug=$ENV{'GAPI_DEBUG'};
|
|
|
|
use XML::LibXML;
|
|
|
|
if (!$ARGV[2]) {
|
|
die "Usage: gapi_pp.pl <srcdir> | gapi2xml.pl <namespace> <outfile> <libname>\n";
|
|
}
|
|
|
|
$ns = $ARGV[0];
|
|
$libname = $ARGV[2];
|
|
|
|
# Used by name mangling sub
|
|
%num2txt = ('1', "One", '2', "Two", '3', "Three", '4', "Four", '5', "Five",
|
|
'6', "Six", '7', "Seven", '8', "Eight", '9', "Nine", '0', "Zero");
|
|
|
|
##############################################################
|
|
# Check if the filename provided exists. We parse existing files into
|
|
# a tree and append the namespace to the root node. If the file doesn't
|
|
# exist, we create a doc tree and root node to work with.
|
|
##############################################################
|
|
|
|
if (-e $ARGV[1]) {
|
|
#parse existing file and get root node.
|
|
$doc = XML::LibXML->new->parse_file($ARGV[1]);
|
|
$root = $doc->getDocumentElement();
|
|
if ($root->getAttribute ('parser_version') != $parser_version) {
|
|
die "The version of the file does not match the version of the parser";
|
|
}
|
|
} else {
|
|
$doc = XML::LibXML::Document->new();
|
|
$root = $doc->createElement('api');
|
|
$root->setAttribute('parser_version', $parser_version);
|
|
$doc->setDocumentElement($root);
|
|
$warning_node = XML::LibXML::Comment->new ("\n\n This file was automatically generated.\n Please DO NOT MODIFY THIS FILE, modify .metadata files instead.\n\n");
|
|
$root->appendChild($warning_node);
|
|
}
|
|
|
|
$ns_elem = $doc->createElement('namespace');
|
|
$ns_elem->setAttribute('name', $ns);
|
|
$ns_elem->setAttribute('library', $libname);
|
|
$root->appendChild($ns_elem);
|
|
|
|
##############################################################
|
|
# First we parse the input for typedefs, structs, enums, and class_init funcs
|
|
# and put them into temporary hashes.
|
|
##############################################################
|
|
|
|
while ($line = <STDIN>) {
|
|
if ($line =~ /typedef\s+(struct\s+\w+\s+)\*+(\w+);/) {
|
|
$ptrs{$2} = $1;
|
|
} elsif ($line =~ /typedef\s+(struct\s+\w+)\s+(\w+);/) {
|
|
next if ($2 =~ /Private$/);
|
|
# fixme: siiigh
|
|
$2 = "GdkDrawable" if ($1 eq "_GdkDrawable");
|
|
$types{$2} = $1;
|
|
} elsif ($line =~ /typedef\s+struct/) {
|
|
$sdef = $line;
|
|
while ($line = <STDIN>) {
|
|
$sdef .= $line;
|
|
last if ($line =~ /^(deprecated)?}/);
|
|
}
|
|
$sdef =~ s!/\*.*?(\*/|\n)!!g;
|
|
$sdef =~ s/\n\s*//g;
|
|
$types{$1} = $sdef if ($sdef =~ /.*\}\s*(\w+);/);
|
|
} elsif ($line =~ /typedef\s+(unsigned\s+\w+)\s+(\**)(\w+);/) {
|
|
$types{$3} = $1 . $2;
|
|
} elsif ($line =~ /typedef\s+(\w+)\s+(\**)(\w+);/) {
|
|
$types{$3} = $1 . $2;
|
|
} elsif ($line =~ /typedef\s+enum\s+(\w+)\s+(\w+);/) {
|
|
$etypes{$1} = $2;
|
|
} elsif ($line =~ /^((deprecated)?typedef\s+)?\benum\b/) {
|
|
$edef = $line;
|
|
while ($line = <STDIN>) {
|
|
$edef .= $line;
|
|
last if ($line =~ /^(deprecated)?}\s*(\w+)?;/);
|
|
}
|
|
$edef =~ s/\n\s*//g;
|
|
$edef =~ s|/\*.*?\*/||g;
|
|
if ($edef =~ /typedef.*}\s*(\w+);/) {
|
|
$ename = $1;
|
|
} elsif ($edef =~ /^(deprecated)?enum\s+(\w+)\s*{/) {
|
|
$ename = $2;
|
|
} else {
|
|
print "Unexpected enum format\n$edef";
|
|
next;
|
|
}
|
|
$edefs{$ename} = $edef;
|
|
} elsif ($line =~ /typedef\s+(const\s+)?\w+\s*\**\s*\(\s*\*\s*(\w+)\s*\)\s*\(/) {
|
|
$fname = $2;
|
|
$fdef = "";
|
|
while ($line !~ /;/) {
|
|
$fdef .= $line;
|
|
$line = <STDIN>;
|
|
}
|
|
$fdef .= $line;
|
|
$fdef =~ s/\n\s+//g;
|
|
$fpdefs{$fname} = $fdef;
|
|
} elsif ($line =~ /^(private|deprecated)?struct\s+(\w+)/) {
|
|
next if ($line =~ /;/);
|
|
$sname = $2;
|
|
$sdef = $line;
|
|
while ($line = <STDIN>) {
|
|
$sdef .= $line;
|
|
last if ($line =~ /^(deprecated)?}/);
|
|
}
|
|
$sdef =~ s!/\*[^<].*?(\*/|\n)!!g;
|
|
$sdef =~ s/\n\s*//g;
|
|
$sdefs{$sname} = $sdef if (!exists ($sdefs{$sname}));
|
|
} elsif ($line =~ /^(\w+)_(class|base|default)_init\b/) {
|
|
$class = StudlyCaps($1);
|
|
$pedef = $line;
|
|
while ($line = <STDIN>) {
|
|
$pedef .= $line;
|
|
last if ($line =~ /^(deprecated)?}/);
|
|
}
|
|
$pedefs{lc($class)} = $pedef;
|
|
} elsif ($line =~ /^(\w+)_get_type\b/) {
|
|
$class = StudlyCaps($1);
|
|
$pedef = $line;
|
|
while ($line = <STDIN>) {
|
|
$pedef .= $line;
|
|
if ($line =~ /g_boxed_type_register_static/) {
|
|
$boxdef = $line;
|
|
while ($line !~ /;/) {
|
|
$boxdef .= ($line = <STDIN>);
|
|
}
|
|
$boxdef =~ s/\n\s*//g;
|
|
$boxdef =~ /\(\"(\w+)\"/;
|
|
my $boxtype = $1;
|
|
$boxtype =~ s/($ns)Type(\w+)/$ns$2/;
|
|
$boxdefs{$boxtype} = $boxdef;
|
|
} elsif ($line =~ /g_(enum|flags)_register_static/) {
|
|
$pedef =~ /^(\w+_get_type)/;
|
|
$enum_gtype{$class} = $1;
|
|
}
|
|
last if ($line =~ /^(deprecated)?}/);
|
|
}
|
|
$typefuncs{lc($class)} = $pedef;
|
|
} elsif ($line =~ /^G_DEFINE_TYPE_(EXTENDED|WITH_CODE)\s*\(\s*(\w+)/) {
|
|
$typefuncs{lc($2)} = $line;
|
|
} elsif ($line =~ /^G_DEFINE_BOXED_TYPE\s*\(\s*(\w+)/) {
|
|
$boxdefs{$1} = $line;
|
|
} elsif ($line =~ /^G_DEFINE_INTERFACE\s*\(\s*(\w+)\s*,\s*(\w+)/) {
|
|
if (exists($get_types{"$2_get_type"})) {
|
|
$typedef = $get_types{"$2_get_type"};
|
|
if (!exists($ifaces{$typedef})) {
|
|
$ifaces{$typedef} = "$1Interface";
|
|
}
|
|
}
|
|
} elsif ($line =~ /^(deprecated)?(const|G_CONST_RETURN)?\s*(struct\s+)?\w+\s*\**(\s*(const|G_CONST_RETURN)\s*\**)?\s*(\w+)\s*\(/) {
|
|
$fname = $6;
|
|
$fdef = "";
|
|
while ($line !~ /;/) {
|
|
$fdef .= $line;
|
|
$line = <STDIN>;
|
|
}
|
|
$fdef .= $line;
|
|
$fdef =~ s/\n\s*//g;
|
|
if ($fdef !~ /^_/) {
|
|
$fdefs{$fname} = $fdef;
|
|
}
|
|
} elsif ($line =~ /CHECK_(\w*)CAST/) {
|
|
$cast_macro = $line;
|
|
while ($line =~ /\\$/) {
|
|
$line = <STDIN>;
|
|
$cast_macro .= $line;
|
|
}
|
|
$cast_macro =~ s/\\\n\s*//g;
|
|
$cast_macro =~ s/\s+/ /g;
|
|
if ($cast_macro =~ /G_TYPE_CHECK_(\w+)_CAST.*,\s*(\w+),\s*(\w+)\)/) {
|
|
if ($1 eq "INSTANCE") {
|
|
$objects{$2} = $3 . $objects{$2};
|
|
} else {
|
|
$objects{$2} .= ":$3";
|
|
}
|
|
} elsif ($cast_macro =~ /G_TYPE_CHECK_(\w+)_CAST.*,\s*([a-zA-Z0-9]+)_(\w+)_get_type\s*\(\),\s*(\w+)\)/) {
|
|
$typename = uc ("$2_type_$3");
|
|
if ($1 eq "INSTANCE") {
|
|
$objects{$typename} = $4 . $objects{$typename};
|
|
} else {
|
|
$objects{$typename} .= ":$4";
|
|
}
|
|
} elsif ($cast_macro =~ /GTK_CHECK_CAST.*,\s*(\w+),\s*(\w+)/) {
|
|
$objects{$1} = $2 . $objects{$1};
|
|
} elsif ($cast_macro =~ /GTK_CHECK_CLASS_CAST.*,\s*(\w+),\s*(\w+)/) {
|
|
$objects{$1} .= ":$2";
|
|
} elsif ($cast_macro =~ /GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_CAST.*,\s*(\w+),\s*(\w+)/) {
|
|
$objects{$1} = $2 . $objects{$1};
|
|
}
|
|
} elsif ($line =~ /INSTANCE_GET_INTERFACE.*,\s*(\w+),\s*(\w+)/) {
|
|
$ifaces{$1} = $2;
|
|
} elsif ($line =~ /^BUILTIN\s*\{\s*\"(\w+)\".*GTK_TYPE_BOXED/) {
|
|
$boxdefs{$1} = $line;
|
|
} elsif ($line =~ /^BUILTIN\s*\{\s*\"(\w+)\".*GTK_TYPE_(ENUM|FLAGS)/) {
|
|
# ignoring these for now.
|
|
} elsif ($line =~ /^(deprecated)?\#\s*define/) {
|
|
my $test_ns = uc ($ns);
|
|
if ($line =~ /^deprecated\#\s*define\s+(\w+)\s+\"(.*)\"/) {
|
|
$defines{"deprecated$1"} = $2;
|
|
} elsif ($line =~ /\#\s*define\s+(\w+)\s+\"(.*)\"/) {
|
|
$defines{$1} = $2;
|
|
} elsif ($line =~ /\#\s*define\s+(\w+)\s+\(?\s*(\w+_get_type)/) {
|
|
$get_types{$2} = $1;
|
|
}
|
|
} elsif ($line !~ /\/\*/) {
|
|
print $line;
|
|
}
|
|
}
|
|
|
|
##############################################################
|
|
# Produce the enum definitions.
|
|
##############################################################
|
|
%enums = ();
|
|
|
|
foreach $cname (sort(keys(%edefs))) {
|
|
$ecnt++;
|
|
$def = $edefs{$cname};
|
|
$cname = $etypes{$cname} if (exists($etypes{$cname}));
|
|
$enums{lc($cname)} = $cname;
|
|
$enum_elem = addNameElem($ns_elem, 'enum', $cname, $ns);
|
|
if ($def =~ /^deprecated/) {
|
|
$enum_elem->setAttribute("deprecated", "1");
|
|
$def =~ s/deprecated//g;
|
|
}
|
|
if ($enum_gtype{$cname}) {
|
|
$enum_elem->setAttribute("gtype", $enum_gtype{$cname});
|
|
}
|
|
if ($def =~ /<</) {
|
|
$enum_elem->setAttribute('type', "flags");
|
|
} else {
|
|
$enum_elem->setAttribute('type', "enum");
|
|
}
|
|
$def =~ /\{(.*\S)\s*\}/;
|
|
@vals = split(/,\s*/, $1);
|
|
$vals[0] =~ s/^\s+//;
|
|
@nameandval = split(/=/, $vals[0]);
|
|
@v0 = split(/_/, $nameandval[0]);
|
|
if (@vals > 1) {
|
|
$done = 0;
|
|
for ($idx = 0, $regex = ""; $idx < @v0; $idx++) {
|
|
$regex .= ($v0[$idx] . "_");
|
|
foreach $val (@vals) {
|
|
$done = 1 if ($val !~ /$regex/);
|
|
}
|
|
last if $done;
|
|
}
|
|
$common = join("_", @v0[0..$idx-1]);
|
|
} else {
|
|
$common = join("_", @v0[0..$#v0-1]);
|
|
}
|
|
|
|
foreach $val (@vals) {
|
|
$val =~ s/=\s*\(\s*(.*\S)\s*\)\s*/= \1/;
|
|
if ($val =~ /$common\_?(\w+)\s*=\s*(.*)$/) {
|
|
$name = $1;
|
|
$enumval = $2;
|
|
if ($enumval =~ /^(\d+|0x[0-9A-Fa-f]+)u?\s*<<\s*(\d+)$/) {
|
|
$enumval = "$1 << $2";
|
|
} elsif ($enumval =~ /^$common\_?(\w+)$/) {
|
|
$enumval = StudlyCaps(lc($1))
|
|
}
|
|
} elsif ($val =~ /$common\_?(\w+)/) {
|
|
$name = $1; $enumval = "";
|
|
} else {
|
|
die "Unexpected enum value: $val for common value $common\n";
|
|
}
|
|
|
|
$val_elem = addNameElem($enum_elem, 'member');
|
|
$val_elem->setAttribute('cname', "$common\_$name");
|
|
$val_elem->setAttribute('name', StudlyCaps(lc($name)));
|
|
if ($enumval) {
|
|
$val_elem->setAttribute('value', $enumval);
|
|
}
|
|
}
|
|
}
|
|
|
|
##############################################################
|
|
# Parse the callbacks.
|
|
##############################################################
|
|
|
|
foreach $cbname (sort(keys(%fpdefs))) {
|
|
next if ($cbname =~ /^_/);
|
|
$cbcnt++;
|
|
$fdef = $cb = $fpdefs{$cbname};
|
|
$cb_elem = addNameElem($ns_elem, 'callback', $cbname, $ns);
|
|
$cb =~ /typedef\s+(.*)\(.*\).*\((.*)\);/;
|
|
$ret = $1; $params = $2;
|
|
addReturnElem($cb_elem, $ret);
|
|
if ($params && ($params ne "void")) {
|
|
addParamsElem($cb_elem, split(/,/, $params));
|
|
}
|
|
}
|
|
|
|
##############################################################
|
|
# Parse the interfaces list.
|
|
##############################################################
|
|
|
|
foreach $type (sort(keys(%ifaces))) {
|
|
|
|
$iface = $ifaces{$type};
|
|
($inst, $dontcare) = split(/:/, delete $objects{$type});
|
|
$initfunc = $pedefs{lc($inst)};
|
|
$ifacetype = delete $types{$iface};
|
|
delete $types{$inst};
|
|
|
|
$ifacecnt++;
|
|
$iface_el = addNameElem($ns_elem, 'interface', $inst, $ns);
|
|
|
|
$elem_table{lc($inst)} = $iface_el;
|
|
|
|
if ($ifacetype =~ /struct\s+(\w+)/) {
|
|
$classdef = $sdefs{$1};
|
|
} else {
|
|
$classdef = 0;
|
|
}
|
|
|
|
if ($classdef) {
|
|
my @signal_vms;
|
|
if ($initfunc) {
|
|
@signal_vms = parseInitFunc($iface_el, $initfunc, $classdef);
|
|
} else {
|
|
warn "Don't have an init func for $inst.\n" if $debug;
|
|
# my @signal_vms;
|
|
}
|
|
addClassElem ($iface_el, $classdef, @signal_vms);
|
|
} else {
|
|
$iface_el->setAttribute("consume_only", "1");
|
|
}
|
|
}
|
|
|
|
|
|
##############################################################
|
|
# Parse the classes by walking the objects list.
|
|
##############################################################
|
|
|
|
foreach $type (sort(keys(%objects))) {
|
|
($inst, $class) = split(/:/, $objects{$type});
|
|
$class = $inst . "Class" if (!$class);
|
|
$initfunc = $pedefs{lc($inst)};
|
|
$typefunc = $typefuncs{lc($inst)};
|
|
$insttype = delete $types{$inst};
|
|
$classtype = delete $types{$class};
|
|
|
|
$instdef = $classdef = "";
|
|
$instdef = $sdefs{$1} if ($insttype =~ /struct\s+(\w+)/);
|
|
$classdef = $sdefs{$1} if ($classtype =~ /struct\s+(\w+)/);
|
|
$classdef =~ s/deprecated//g;
|
|
$instdef =~ s/\s+(\*+)([^\/])/\1 \2/g;
|
|
warn "Strange Class $inst\n" if (!$instdef && $debug);
|
|
|
|
$classcnt++;
|
|
$obj_el = addNameElem($ns_elem, 'object', $inst, $ns);
|
|
|
|
$elem_table{lc($inst)} = $obj_el;
|
|
|
|
# Check if the object is deprecated
|
|
if ($instdef =~ /^deprecatedstruct/) {
|
|
$obj_el->setAttribute("deprecated", "1");
|
|
$instdef =~ s/deprecated//g;
|
|
}
|
|
|
|
# Extract parent and fields from the struct
|
|
if ($instdef =~ /^struct/) {
|
|
$instdef =~ /\{(.*)\}/;
|
|
$fieldstr = $1;
|
|
$fieldstr =~ s|/\*[^<].*?\*/||g;
|
|
@fields = split(/;/, $fieldstr);
|
|
addFieldElems($obj_el, 'private', @fields);
|
|
$obj_el->setAttribute('parent', $obj_el->firstChild->getAttribute('type'));
|
|
$obj_el->removeChild($obj_el->firstChild);
|
|
} elsif ($instdef =~ /privatestruct/) {
|
|
# just get the parent for private structs
|
|
$instdef =~ /\{\s*(\w+)/;
|
|
$obj_el->setAttribute('parent', "$1");
|
|
}
|
|
|
|
# Get the props from the class_init func.
|
|
if ($initfunc) {
|
|
@signal_vms = parseInitFunc($obj_el, $initfunc, $classdef);
|
|
} else {
|
|
warn "Don't have an init func for $inst.\n" if $debug;
|
|
}
|
|
|
|
addClassElem ($obj_el, $classdef, @signal_vms) if ($classdef);
|
|
|
|
# Get the interfaces from the class_init func.
|
|
if ($typefunc) {
|
|
if ($typefunc =~ /G_DEFINE_TYPE_(EXTENDED|WITH_CODE)/) {
|
|
parseTypeFuncMacro($obj_el, $typefunc);
|
|
} else {
|
|
parseTypeFunc($obj_el, $typefunc);
|
|
}
|
|
} else {
|
|
warn "Don't have a GetType func for $inst.\n" if $debug;
|
|
}
|
|
|
|
}
|
|
|
|
##############################################################
|
|
# Parse the remaining types.
|
|
##############################################################
|
|
|
|
foreach $key (sort (keys (%types))) {
|
|
|
|
$lasttype = $type = $key;
|
|
while ($type && ($types{$type} !~ /struct/)) {
|
|
$lasttype = $type;
|
|
$type = $types{$type};
|
|
}
|
|
|
|
if ($types{$type} =~ /struct\s+(\w+)/) {
|
|
$type = $1;
|
|
if (exists($sdefs{$type})) {
|
|
$def = $sdefs{$type};
|
|
} else {
|
|
$def = "privatestruct";
|
|
}
|
|
} elsif ($types{$type} =~ /struct/ && $type =~ /^$ns/) {
|
|
$def = $types{$type};
|
|
} else {
|
|
$elem = addNameElem($ns_elem, 'alias', $key, $ns);
|
|
$elem->setAttribute('type', $lasttype);
|
|
warn "alias $key to $lasttype\n" if $debug;
|
|
next;
|
|
}
|
|
|
|
# fixme: hack
|
|
if ($key eq "GdkBitmap") {
|
|
$struct_el = addNameElem($ns_elem, 'object', $key, $ns);
|
|
} elsif (exists($boxdefs{$key})) {
|
|
$struct_el = addNameElem($ns_elem, 'boxed', $key, $ns);
|
|
} else {
|
|
$struct_el = addNameElem($ns_elem, 'struct', $key, $ns);
|
|
}
|
|
|
|
if ($def =~ /^deprecated/) {
|
|
$struct_el->setAttribute("deprecated", "1");
|
|
$def =~ s/deprecated//g;
|
|
}
|
|
|
|
$elem_table{lc($key)} = $struct_el;
|
|
|
|
$def =~ s/\s+/ /g;
|
|
if ($def =~ /privatestruct/) {
|
|
$struct_el->setAttribute('opaque', 'true');
|
|
} else {
|
|
$def =~ /\{(.+)\}/;
|
|
addFieldElems($struct_el, 'public', split(/;/, $1));
|
|
}
|
|
}
|
|
|
|
# really, _really_ opaque structs that aren't even defined in sources. Lovely.
|
|
foreach $key (sort (keys (%ptrs))) {
|
|
next if $ptrs{$key} !~ /struct\s+(\w+)/;
|
|
$type = $1;
|
|
$struct_el = addNameElem ($ns_elem, 'struct', $key, $ns);
|
|
$struct_el->setAttribute('opaque', 'true');
|
|
$elem_table{lc($key)} = $struct_el;
|
|
}
|
|
|
|
addFuncElems();
|
|
addStaticFuncElems();
|
|
|
|
# This should probably be done in a more generic way
|
|
foreach $define (sort (keys (%defines))) {
|
|
next if $define !~ /[A-Z]_STOCK_/;
|
|
if ($stocks{$ns}) {
|
|
$stock_el = $stocks{$ns};
|
|
} else {
|
|
$stock_el = addNameElem($ns_elem, "object", $ns . "Stock", $ns);
|
|
$stocks{$ns} = $stock_el;
|
|
}
|
|
$string_el = addNameElem ($stock_el, "static-string", $define);
|
|
$string_name = lc($define);
|
|
$string_name =~ s/\w+_stock_//;
|
|
$string_el->setAttribute('name', StudlyCaps($string_name));
|
|
$string_el->setAttribute('value', $defines{$define});
|
|
}
|
|
|
|
##############################################################
|
|
# Output the tree
|
|
##############################################################
|
|
|
|
if ($ARGV[1]) {
|
|
open(XMLFILE, ">$ARGV[1]") || die "Couldn't open $ARGV[1] for writing.\n";
|
|
print XMLFILE $doc->toString();
|
|
close(XMLFILE);
|
|
} else {
|
|
print $doc->toString();
|
|
}
|
|
|
|
##############################################################
|
|
# Generate a few stats from the parsed source.
|
|
##############################################################
|
|
|
|
$scnt = keys(%sdefs); $fcnt = keys(%fdefs); $tcnt = keys(%types);
|
|
print "structs: $scnt enums: $ecnt callbacks: $cbcnt\n";
|
|
print "funcs: $fcnt types: $tcnt classes: $classcnt\n";
|
|
print "props: $propcnt childprops: $childpropcnt signals: $sigcnt\n\n";
|
|
|
|
sub addClassElem
|
|
{
|
|
my ($obj_el, $classdef, @signal_vms) = @_;
|
|
|
|
my %is_signal_vm;
|
|
for (@signal_vms) {
|
|
$is_signal_vm{$_} = 1;
|
|
}
|
|
|
|
if ($classdef =~ /struct\s+_?(\w+)\s*{(.*)};/) {
|
|
my $elem = $doc->createElement('class_struct');
|
|
$elem->setAttribute('cname', $1);
|
|
$obj_el->insertBefore($elem, $obj_el->firstChild);
|
|
$fields = $2;
|
|
$fields =~ s!/\*.*?\*/!!g; # Remove comments
|
|
foreach $field (split (/;/, $fields)) {
|
|
if ($field =~ /\s*(G_CONST_RETURN\s+)?(\S+\s*\**)\s*\(\s*\*\s*(\w+)\s*\)\s*(\((.*?)\))?/) {
|
|
$ret = $1 . $2; $cname = $3; $parms = $5;
|
|
|
|
$class_elem = $doc->createElement('method');
|
|
$elem->appendChild($class_elem);
|
|
|
|
if ($is_signal_vm{$cname}) {
|
|
$class_elem->setAttribute('signal_vm', $cname);
|
|
} else {
|
|
$class_elem->setAttribute('vm', $cname);
|
|
|
|
$vm_elem = $doc->createElement('virtual_method');
|
|
$obj_el->appendChild($vm_elem);
|
|
$vm_elem->setAttribute('name', StudlyCaps($cname));
|
|
$vm_elem->setAttribute('cname', $cname);
|
|
|
|
addReturnElem($vm_elem, $ret);
|
|
|
|
if ($parms && ($parms ne "void")) { # if there are any parameters
|
|
@parm_arr = split(/,/, $parms);
|
|
$parms =~ /\s*(\w+)/; # Get type of first parameter
|
|
if ($1 ne $obj_el->getAttribute ('cname')) {
|
|
$vm_elem->setAttribute('shared', 'true'); # First parameter is not of the type of the declaring class -> static vm
|
|
} else {
|
|
($dump, @parm_arr) = @parm_arr;
|
|
}
|
|
addParamsElem($vm_elem, @parm_arr);
|
|
} else {
|
|
$vm_elem->setAttribute('shared', 'true');
|
|
}
|
|
|
|
if ($cname =~ /reserved_?[0-9]+$/ || $cname =~ /padding_?[0-9]+$/ || $cname =~ /recent_?[0-9]+$/) {
|
|
$vm_elem->setAttribute('padding', 'true');
|
|
}
|
|
}
|
|
} elsif ($field =~ /(unsigned\s+)?(const\s+)?(\S+)\s+(.+)/) {
|
|
my $unsigned = $1; $const = $2; $name = $3; $symb = $4;
|
|
$const =~ s/const\s+/const\-/g;
|
|
my $type = $unsigned . $const . $name;
|
|
|
|
foreach $tok (split (/,\s*/, $symb)) { # multiple field defs may occur in one line; like int xrange, yrange;
|
|
$tok =~ /(\*)?(\w+)\s*(.*)/;
|
|
my $field_type = $type . $1; my $cname = $2; my $modifiers = $3;
|
|
|
|
$fld_elem = addNameElem($elem, 'field', $cname, "");
|
|
$fld_elem->setAttribute('type', "$field_type");
|
|
|
|
if ($modifiers =~ /\[(.*)\]/) {
|
|
$fld_elem->setAttribute('array_len', "$1");
|
|
} elsif ($modifiers =~ /\:\s*(\d+)/) {
|
|
$fld_elem->setAttribute('bits', "$1");
|
|
}
|
|
}
|
|
} elsif ($field =~ /\S+/) {
|
|
print "***** Unmatched class struct field $field\n";
|
|
}
|
|
}
|
|
} else {
|
|
print "***** Unmatched $classdef\n";
|
|
}
|
|
}
|
|
|
|
sub addFieldElems
|
|
{
|
|
my ($parent, $defaultaccess, @fields) = @_;
|
|
my $access = $defaultaccess;
|
|
|
|
foreach $field (@fields) {
|
|
if ($field =~ m!/\*< (public|private) >.*\*/(.*)$!) {
|
|
$access = $1;
|
|
$field = $2;
|
|
}
|
|
next if ($field !~ /\S/);
|
|
$field =~ s/GSEAL\s*\((.*)\)/\1/g;
|
|
$field =~ s/\bvolatile\s+//g;
|
|
$field =~ s/\s+(\*+)/\1 /g;
|
|
$field =~ s/(const\s+)?(\w+)\*\s+const\*/const \2\*/g;
|
|
$field =~ s/(\w+)\s+const\s*\*/const \1\*/g;
|
|
$field =~ s/const /const\-/g;
|
|
$field =~ s/struct /struct\-/g;
|
|
$field =~ s/.*\*\///g;
|
|
next if ($field !~ /\S/);
|
|
|
|
if ($field =~ /(\S+\s+\*?)\(\*\s*(.+)\)\s*\((.*)\)/) {
|
|
$elem = addNameElem($parent, 'callback', $2);
|
|
addReturnElem($elem, $1);
|
|
addParamsElem($elem, $3);
|
|
} elsif ($field =~ /(unsigned )?(\S+)\s+(.+)/) {
|
|
my $type = $1 . $2; $symb = $3;
|
|
foreach $tok (split (/,\s*/, $symb)) {
|
|
if ($tok =~ /(\w+)\s*\[(.*)\]/) {
|
|
$elem = addNameElem($parent, 'field', $1, "");
|
|
$elem->setAttribute('array_len', "$2");
|
|
} elsif ($tok =~ /(\w+)\s*\:\s*(\d+)/) {
|
|
$elem = addNameElem($parent, 'field', $1, "");
|
|
$elem->setAttribute('bits', "$2");
|
|
} else {
|
|
$elem = addNameElem($parent, 'field', $tok, "");
|
|
}
|
|
$elem->setAttribute('type', "$type");
|
|
|
|
if ($access ne $defaultaccess) {
|
|
$elem->setAttribute('access', "$access");
|
|
}
|
|
}
|
|
} else {
|
|
die "$field\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
sub addFuncElems
|
|
{
|
|
my ($obj_el, $inst, $prefix);
|
|
|
|
$fcnt = keys(%fdefs);
|
|
|
|
foreach $mname (sort (keys (%fdefs))) {
|
|
next if ($mname =~ /^_/);
|
|
$obj_el = "";
|
|
$prefix = $mname;
|
|
$prepend = undef;
|
|
while ($prefix =~ /(\w+)_/) {
|
|
$prefix = $key = $1;
|
|
$key =~ s/_//g;
|
|
# FIXME: lame Gdk API hack
|
|
if ($key eq "gdkdraw") {
|
|
$key = "gdkdrawable";
|
|
$prepend = "draw_";
|
|
}
|
|
if (exists ($elem_table{$key})) {
|
|
$prefix .= "_";
|
|
$obj_el = $elem_table{$key};
|
|
$inst = $key;
|
|
last;
|
|
} elsif (exists ($enums{$key}) && ($mname =~ /_get_type/)) {
|
|
delete $fdefs{$mname};
|
|
last;
|
|
}
|
|
}
|
|
next if (!$obj_el);
|
|
|
|
$mdef = delete $fdefs{$mname};
|
|
|
|
if ($mname =~ /$prefix(new)/) {
|
|
$el = addNameElem($obj_el, 'constructor', $mname);
|
|
if ($mdef =~ /^deprecated/) {
|
|
$el->setAttribute("deprecated", "1");
|
|
$mdef =~ s/deprecated//g;
|
|
}
|
|
$drop_1st = 0;
|
|
} else {
|
|
$el = addNameElem($obj_el, 'method', $mname, $prefix, $prepend);
|
|
if ($mdef =~ /^deprecated/) {
|
|
$el->setAttribute("deprecated", "1");
|
|
$mdef =~ s/deprecated//g;
|
|
}
|
|
$mdef =~ /(.*?)\w+\s*\(/;
|
|
addReturnElem($el, $1);
|
|
$mdef =~ /\(\s*(const)?\s*(\w+)/;
|
|
if (lc($2) ne $inst) {
|
|
$el->setAttribute("shared", "true");
|
|
$drop_1st = 0;
|
|
} else {
|
|
$drop_1st = 1;
|
|
}
|
|
}
|
|
|
|
parseParms ($el, $mdef, $drop_1st);
|
|
|
|
# Don't add "free" to this regexp; that will wrongly catch all boxed types
|
|
if ($mname =~ /$prefix(new|destroy|ref|unref)/ &&
|
|
($obj_el->nodeName eq "boxed" || $obj_el->nodeName eq "struct") &&
|
|
$obj_el->getAttribute("opaque") ne "true") {
|
|
$obj_el->setAttribute("opaque", "true");
|
|
for my $field ($obj_el->getElementsByTagName("field")) {
|
|
if (!$field->getAttribute("access")) {
|
|
$field->setAttribute("access", "public");
|
|
$field->setAttribute("writeable", "true");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sub parseParms
|
|
{
|
|
my ($el, $mdef, $drop_1st) = @_;
|
|
|
|
$fmt_args = 0;
|
|
|
|
if ($mdef =~ /G_GNUC_PRINTF.*\((\d+,\s*\d+)\s*\)/) {
|
|
$fmt_args = $1;
|
|
$mdef =~ s/\s*G_GNUC_PRINTF.*\)//;
|
|
}
|
|
|
|
if (($mdef =~ /\((.*)\)/) && ($1 ne "void")) {
|
|
@parms = ();
|
|
$parm = "";
|
|
$pcnt = 0;
|
|
foreach $char (split(//, $1)) {
|
|
if ($char eq "(") {
|
|
$pcnt++;
|
|
} elsif ($char eq ")") {
|
|
$pcnt--;
|
|
} elsif (($pcnt == 0) && ($char eq ",")) {
|
|
@parms = (@parms, $parm);
|
|
$parm = "";
|
|
next;
|
|
}
|
|
$parm .= $char;
|
|
}
|
|
|
|
if ($parm) {
|
|
@parms = (@parms, $parm);
|
|
}
|
|
# @parms = split(/,/, $1);
|
|
($dump, @parms) = @parms if $drop_1st;
|
|
if (@parms > 0) {
|
|
addParamsElem($el, @parms);
|
|
}
|
|
|
|
if ($fmt_args != 0) {
|
|
$fmt_args =~ /(\d+),\s*(\d+)/;
|
|
$fmt = $1; $args = $2;
|
|
($params_el, @junk) = $el->getElementsByTagName ("parameters");
|
|
(@params) = $params_el->getElementsByTagName ("parameter");
|
|
$offset = 1 + $drop_1st;
|
|
$params[$fmt-$offset]->setAttribute ("printf_format", "true");
|
|
$params[$args-$offset]->setAttribute ("printf_format_args", "true");
|
|
}
|
|
}
|
|
}
|
|
|
|
sub addStaticFuncElems
|
|
{
|
|
my ($global_el, $ns_prefix);
|
|
|
|
@mnames = sort (keys (%fdefs));
|
|
$mcount = @mnames;
|
|
|
|
return if ($mcount == 0);
|
|
|
|
$ns_prefix = "";
|
|
$global_el = "";
|
|
|
|
for ($i = 0; $i < $mcount; $i++) {
|
|
$mname = $mnames[$i];
|
|
$prefix = $mname;
|
|
next if ($prefix =~ /^_/);
|
|
|
|
if ($ns_prefix eq "") {
|
|
my (@toks) = split(/_/, $prefix);
|
|
for ($j = 0; $j < @toks; $j++) {
|
|
if (join ("", @toks[0 .. $j]) eq lc($ns)) {
|
|
$ns_prefix = join ("_", @toks[0 .. $j]);
|
|
last;
|
|
}
|
|
}
|
|
next if ($ns_prefix eq "");
|
|
}
|
|
next if ($mname !~ /^$ns_prefix/);
|
|
|
|
if ($mname =~ /($ns_prefix)_([a-zA-Z]+)_\w+/) {
|
|
$classname = $2;
|
|
$key = $prefix = $1 . "_" . $2 . "_";
|
|
$key =~ s/_//g;
|
|
$cnt = 1;
|
|
if (exists ($enums{$key})) {
|
|
$cnt = 1;
|
|
} elsif ($classname ne "set" && $classname ne "get" &&
|
|
$classname ne "scan" && $classname ne "find" &&
|
|
$classname ne "add" && $classname ne "remove" &&
|
|
$classname ne "free" && $classname ne "register" &&
|
|
$classname ne "execute" && $classname ne "show" &&
|
|
$classname ne "parse" && $classname ne "paint" &&
|
|
$classname ne "string") {
|
|
while ($mnames[$i+$cnt] =~ /$prefix/) { $cnt++; }
|
|
}
|
|
if ($cnt == 1) {
|
|
$mdef = delete $fdefs{$mname};
|
|
|
|
if (!$global_el) {
|
|
$global_el = $doc->createElement('class');
|
|
$global_el->setAttribute('name', "Global");
|
|
$global_el->setAttribute('cname', $ns . "Global");
|
|
$ns_elem->appendChild($global_el);
|
|
}
|
|
$el = addNameElem($global_el, 'method', $mname, $ns_prefix);
|
|
if ($mdef =~ /^deprecated/) {
|
|
$el->setAttribute("deprecated", "1");
|
|
$mdef =~ s/deprecated//g;
|
|
}
|
|
$mdef =~ /(.*?)\w+\s*\(/;
|
|
addReturnElem($el, $1);
|
|
$el->setAttribute("shared", "true");
|
|
parseParms ($el, $mdef, 0);
|
|
next;
|
|
} else {
|
|
$class_el = $doc->createElement('class');
|
|
$class_el->setAttribute('name', StudlyCaps($classname));
|
|
$class_el->setAttribute('cname', StudlyCaps($prefix));
|
|
$ns_elem->appendChild($class_el);
|
|
|
|
for ($j = 0; $j < $cnt; $j++) {
|
|
$mdef = delete $fdefs{$mnames[$i+$j]};
|
|
|
|
$el = addNameElem($class_el, 'method', $mnames[$i+$j], $prefix);
|
|
if ($mdef =~ /^deprecated/) {
|
|
$el->setAttribute("deprecated", "1");
|
|
$mdef =~ s/deprecated//g;
|
|
}
|
|
$mdef =~ /(.*?)\w+\s*\(/;
|
|
addReturnElem($el, $1);
|
|
$el->setAttribute("shared", "true");
|
|
parseParms ($el, $mdef, 0);
|
|
}
|
|
$i += ($cnt - 1);
|
|
next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sub addNameElem
|
|
{
|
|
my ($node, $type, $cname, $prefix, $prepend) = @_;
|
|
|
|
my $elem = $doc->createElement($type);
|
|
$node->appendChild($elem);
|
|
if (defined $prefix) {
|
|
my $match;
|
|
if ($cname =~ /$prefix(\w+)/) {
|
|
$match = $1;
|
|
} else {
|
|
$match = $cname;
|
|
}
|
|
if ($prepend) {
|
|
$name = $prepend . $match;
|
|
} else {
|
|
$name = $match;
|
|
}
|
|
$elem->setAttribute('name', StudlyCaps($name));
|
|
}
|
|
if ($cname) {
|
|
$elem->setAttribute('cname', $cname);
|
|
}
|
|
return $elem;
|
|
}
|
|
|
|
sub addParamsElem
|
|
{
|
|
my ($parent, @params) = @_;
|
|
|
|
my $parms_elem = $doc->createElement('parameters');
|
|
$parent->appendChild($parms_elem);
|
|
my $parm_num = 0;
|
|
foreach $parm (@params) {
|
|
$parm_num++;
|
|
$parm =~ s/\s+(\*+)/\1 /g;
|
|
my $out = $parm =~ s/G_CONST_RETURN/const/g;
|
|
$parm =~ s/(const\s+)?(\w+)\*\s+const\*/const \2\*/g;
|
|
$parm =~ s/(\*+)\s*const\s+/\1 /g;
|
|
$parm =~ s/(\w+)\s+const\s*\*/const \1\*/g;
|
|
$parm =~ s/const\s+/const-/g;
|
|
$parm =~ s/unsigned\s+/unsigned-/g;
|
|
$parm =~ s/\bvolatile\s+//g;
|
|
if ($parm =~ /(.*)\(\s*\**\s*(\w+)\)\s+\((.*)\)/) {
|
|
my $ret = $1; my $cbn = $2; my $params = $3;
|
|
my $type = $parent->getAttribute('name') . StudlyCaps($cbn);
|
|
$cb_elem = addNameElem($ns_elem, 'callback', $type, $ns);
|
|
addReturnElem($cb_elem, $ret);
|
|
if ($params && ($params ne "void")) {
|
|
addParamsElem($cb_elem, split(/,/, $params));
|
|
my $data_parm = $cb_elem->lastChild()->lastChild();
|
|
if ($data_parm && $data_parm->getAttribute('type') eq "gpointer") {
|
|
$data_parm->setAttribute('name', 'data');
|
|
}
|
|
}
|
|
$parm_elem = $doc->createElement('parameter');
|
|
$parm_elem->setAttribute('type', $type);
|
|
$parm_elem->setAttribute('name', $cbn);
|
|
$parms_elem->appendChild($parm_elem);
|
|
next;
|
|
} elsif ($parm =~ /\.\.\./) {
|
|
$parm_elem = $doc->createElement('parameter');
|
|
$parms_elem->appendChild($parm_elem);
|
|
$parm_elem->setAttribute('ellipsis', 'true');
|
|
next;
|
|
}
|
|
$parm_elem = $doc->createElement('parameter');
|
|
$parms_elem->appendChild($parm_elem);
|
|
my $name = "";
|
|
if ($parm =~ /struct\s+(\S+)\s+(\S+)/) {
|
|
$parm_elem->setAttribute('type', $1);
|
|
$name = $2;
|
|
}elsif ($parm =~ /(unsigned )?(\S+)\s+(\S+)/) {
|
|
$parm_elem->setAttribute('type', $1 . $2);
|
|
$name = $3;
|
|
} elsif ($parm =~ /(\w+\*)(\w+)/) {
|
|
$parm_elem->setAttribute('type', $1);
|
|
$name = $2;
|
|
} elsif ($parm =~ /(\S+)/) {
|
|
$parm_elem->setAttribute('type', $1);
|
|
$name = "arg" . $parm_num;
|
|
}
|
|
if ($name =~ /(\w+)\[.*\]/) {
|
|
$name = $1;
|
|
$parm_elem->setAttribute('array', "true");
|
|
}
|
|
if ($out) {
|
|
$parm_elem->setAttribute('pass_as', "out");
|
|
}
|
|
$parm_elem->setAttribute('name', $name);
|
|
}
|
|
}
|
|
|
|
sub addReturnElem
|
|
{
|
|
my ($parent, $ret) = @_;
|
|
|
|
$ret =~ s/(\w+)\s+const\s*\*/const \1\*/g;
|
|
$ret =~ s/const|G_CONST_RETURN/const-/g;
|
|
$ret =~ s/\s+//g;
|
|
$ret =~ s/(const-)?(\w+)\*(const-)\*/const-\2\*\*/g;
|
|
my $ret_elem = $doc->createElement('return-type');
|
|
$parent->appendChild($ret_elem);
|
|
$ret_elem->setAttribute('type', $ret);
|
|
if ($parent->getAttribute('name') eq "Copy" && $ret =~ /\*$/) {
|
|
$ret_elem->setAttribute('owned', 'true');
|
|
}
|
|
return $ret_elem;
|
|
}
|
|
|
|
sub addPropElem
|
|
{
|
|
my ($spec, $node, $is_child) = @_;
|
|
my ($name, $mode, $docs);
|
|
$spec =~ /g_param_spec_(\w+)\s*\((.*)\s*\)\s*\)/;
|
|
my $type = $1;
|
|
my @params = split(/,/, $2);
|
|
|
|
$name = $params[0];
|
|
if ($defines{$name}) {
|
|
$name = $defines{$name};
|
|
} else {
|
|
$name =~ s/\s*\"//g;
|
|
}
|
|
|
|
$mode = $params[$#params];
|
|
|
|
if ($type =~ /boolean|float|double|^u?int|pointer|unichar/) {
|
|
$type = "g$type";
|
|
} elsif ($type =~ /string/) {
|
|
$type = "gchar*";
|
|
} elsif ($type =~ /boxed|object/) {
|
|
$type = $params[$#params-1];
|
|
$type =~ s/TYPE_//;
|
|
$type =~ s/\s+//g;
|
|
$type = StudlyCaps(lc($type));
|
|
} elsif ($type =~ /enum|flags/) {
|
|
$type = $params[$#params-2];
|
|
$type =~ s/TYPE_//;
|
|
$type =~ s/\s+//g;
|
|
$type = StudlyCaps(lc($type));
|
|
}
|
|
|
|
$prop_elem = $doc->createElement($is_child ? "childprop" : "property");
|
|
$node->appendChild($prop_elem);
|
|
$prop_elem->setAttribute('name', StudlyCaps($name));
|
|
$prop_elem->setAttribute('cname', $name);
|
|
$prop_elem->setAttribute('type', $type);
|
|
|
|
$prop_elem->setAttribute('readable', "true") if ($mode =~ /READ/);
|
|
$prop_elem->setAttribute('writeable', "true") if ($mode =~ /WRIT/);
|
|
$prop_elem->setAttribute('construct', "true") if ($mode =~ /CONSTRUCT(?!_)/);
|
|
$prop_elem->setAttribute('construct-only', "true") if ($mode =~ /CONSTRUCT_ONLY/);
|
|
}
|
|
|
|
sub addPropElem2
|
|
{
|
|
my ($spec, $node, $is_child) = @_;
|
|
my ($name, $mode, $docs);
|
|
|
|
$spec =~ /g_param_spec_(\w+)\s*\((.*)\s*\);/;
|
|
my $type = $1;
|
|
my @params = split(/,/, $2);
|
|
|
|
$name = $params[0];
|
|
|
|
if ($defines{$name}) {
|
|
$name = $defines{$name};
|
|
} else {
|
|
$name =~ s/\s*\"//g;
|
|
}
|
|
|
|
$mode = $params[$#params];
|
|
|
|
if ($type =~ /boolean|float|double|^u?int|pointer|unichar/) {
|
|
$type = "g$type";
|
|
} elsif ($type =~ /string/) {
|
|
$type = "gchar*";
|
|
} elsif ($type =~ /boxed|object/) {
|
|
$type = $params[$#params-1];
|
|
$type =~ s/TYPE_//;
|
|
$type =~ s/\s+//g;
|
|
$type = StudlyCaps(lc($type));
|
|
} elsif ($type =~ /enum|flags/) {
|
|
$type = $params[$#params-2];
|
|
$type =~ s/TYPE_//;
|
|
$type =~ s/\s+//g;
|
|
$type = StudlyCaps(lc($type));
|
|
}
|
|
|
|
$prop_elem = $doc->createElement($is_child ? "childprop" : "property");
|
|
$node->appendChild($prop_elem);
|
|
$prop_elem->setAttribute('name', StudlyCaps($name));
|
|
$prop_elem->setAttribute('cname', $name);
|
|
$prop_elem->setAttribute('type', $type);
|
|
|
|
$prop_elem->setAttribute('readable', "true") if ($mode =~ /READ/);
|
|
$prop_elem->setAttribute('writeable', "true") if ($mode =~ /WRIT/);
|
|
$prop_elem->setAttribute('construct', "true") if ($mode =~ /CONSTRUCT(?!_)/);
|
|
$prop_elem->setAttribute('construct-only', "true") if ($mode =~ /CONSTRUCT_ONLY/);
|
|
}
|
|
|
|
sub parseTypeToken
|
|
{
|
|
my ($tok) = @_;
|
|
|
|
if ($tok =~ /G_TYPE_(\w+)/) {
|
|
my $type = $1;
|
|
if ($type eq "NONE") {
|
|
return "void";
|
|
} elsif ($type eq "INT") {
|
|
return "gint32";
|
|
} elsif ($type eq "UINT") {
|
|
return "guint32";
|
|
} elsif ($type eq "ENUM" || $type eq "FLAGS") {
|
|
return "gint32";
|
|
} elsif ($type eq "STRING") {
|
|
return "gchar*";
|
|
} elsif ($type eq "OBJECT") {
|
|
return "GObject*";
|
|
} else {
|
|
return "g" . lc ($type);
|
|
}
|
|
} else {
|
|
$tok =~ s/_TYPE//;
|
|
$tok =~ s/\|.*STATIC_SCOPE//;
|
|
$tok =~ s/\W+//g;
|
|
return StudlyCaps (lc($tok));
|
|
}
|
|
}
|
|
|
|
sub addSignalElem
|
|
{
|
|
my ($spec, $class, $node) = @_;
|
|
$spec =~ s/\n\s*//g; $class =~ s/\n\s*//g;
|
|
|
|
$sig_elem = $doc->createElement('signal');
|
|
$node->appendChild($sig_elem);
|
|
|
|
if ($spec =~ /\(\"([\w\-]+)\"/) {
|
|
$sig_elem->setAttribute('name', StudlyCaps($1));
|
|
$sig_elem->setAttribute('cname', $1);
|
|
}
|
|
$sig_elem->setAttribute('when', $1) if ($spec =~ /_RUN_(\w+)/);
|
|
|
|
$sig_elem->setAttribute('manual', 'true') if ($spec =~ /G_TYPE_POINTER/);
|
|
if ($spec =~ /_OFFSET\s*\(\w+,\s*(\w+)\)/) {
|
|
my $method = $1;
|
|
$sig_elem->setAttribute('field_name', $method);
|
|
|
|
if ($class =~ /;\s*(\/\*< (public|protected|private) >\s*\*\/)?(G_CONST_RETURN\s+)?(\w+\s*\**)\s*\(\s*\*\s*$method\s*\)\s*\((.*?)\);/) {
|
|
$ret = $4; $parms = $5;
|
|
addReturnElem($sig_elem, $ret);
|
|
if ($parms && ($parms ne "void")) {
|
|
my ($dump, @parm_arr) = split (/,/, $parms);
|
|
addParamsElem($sig_elem, @parm_arr);
|
|
}
|
|
return $method;
|
|
} else {
|
|
die "ERROR: Failed to parse method $method from class definition:\n$class";
|
|
}
|
|
} else {
|
|
@args = split(/,/, $spec);
|
|
my $rettype = parseTypeToken ($args[7]);
|
|
addReturnElem($sig_elem, $rettype);
|
|
$parmcnt = $args[8];
|
|
$parmcnt =~ s/.*(\d+).*/\1/;
|
|
$parms_elem = $doc->createElement('parameters');
|
|
$sig_elem->appendChild($parms_elem);
|
|
|
|
for (my $idx = 0; $idx < $parmcnt; $idx++) {
|
|
my $argtype = parseTypeToken ($args[9+$idx]);
|
|
$parm_elem = $doc->createElement('parameter');
|
|
$parms_elem->appendChild($parm_elem);
|
|
$parm_elem->setAttribute('name', "p$idx");
|
|
$parm_elem->setAttribute('type', $argtype);
|
|
}
|
|
return "";
|
|
}
|
|
}
|
|
|
|
sub addImplementsElem
|
|
{
|
|
my ($spec, $node) = @_;
|
|
$spec =~ s/\n\s*//g;
|
|
if ($spec =~ /,\s*(\w+)_TYPE_(\w+),/) {
|
|
$impl_elem = $doc->createElement('interface');
|
|
$name = StudlyCaps (lc ("$1_$2"));
|
|
$impl_elem->setAttribute ("cname", "$name");
|
|
$node->appendChild($impl_elem);
|
|
}
|
|
}
|
|
|
|
|
|
sub parseInitFunc
|
|
{
|
|
my ($obj_el, $initfunc, $classdef) = @_;
|
|
|
|
my @init_lines = split (/\n/, $initfunc);
|
|
my @signal_vms = ();
|
|
|
|
my $linenum = 0;
|
|
my $pspec = "";
|
|
my $pspec_use = 0;
|
|
while ($linenum < @init_lines) {
|
|
|
|
my $line = $init_lines[$linenum];
|
|
|
|
if ($line =~ /#define/) {
|
|
# FIXME: This ignores the bool helper macro thingie.
|
|
} elsif ($line =~ /g_object_(class|interface)_install_prop/) {
|
|
my $prop = $line;
|
|
$pspec_use = 1;
|
|
while ($prop !~ /\)\s*;/) {
|
|
$prop .= $init_lines[++$linenum];
|
|
if ($init_lines[$linenum] =~ /g_param_spec_/) {
|
|
$pspec_use = 0;
|
|
}
|
|
}
|
|
if ($pspec_use) {
|
|
addPropElem2 ($prop.$pspec, $obj_el, 0);
|
|
} else {
|
|
addPropElem ($prop, $obj_el, 0);
|
|
}
|
|
$propcnt++;
|
|
} elsif ($line =~ /gtk_container_class_install_child_property/) {
|
|
my $prop = $line;
|
|
do {
|
|
$prop .= $init_lines[++$linenum];
|
|
} until ($init_lines[$linenum] =~ /\)\s*;/);
|
|
addPropElem ($prop, $obj_el, 1);
|
|
$childpropcnt++;
|
|
} elsif ($line =~ /\bg.*_signal_new/) {
|
|
my $sig = $line;
|
|
do {
|
|
$sig .= $init_lines[++$linenum];
|
|
} until ($init_lines[$linenum] =~ /;/);
|
|
$signal_vm = addSignalElem ($sig, $classdef, $obj_el);
|
|
push (@signal_vms, $signal_vm) if $signal_vm;
|
|
$sigcnt++;
|
|
} elsif ($line =~ /g_param_spec_/) {
|
|
$pspec = $line;
|
|
do {
|
|
$pspec .= $init_lines[++$linenum];
|
|
} until ($init_lines[$linenum] =~ /\)\s*;/);
|
|
}
|
|
$linenum++;
|
|
}
|
|
return @signal_vms;
|
|
}
|
|
|
|
sub parseTypeFuncMacro
|
|
{
|
|
my ($obj_el, $typefunc) = @_;
|
|
|
|
$impls_node = undef;
|
|
while ($typefunc =~ /G_IMPLEMENT_INTERFACE\s*\(\s*(\w+)/) {
|
|
$iface = $1;
|
|
if (not $impls_node) {
|
|
$impls_node = $doc->createElement ("implements");
|
|
$obj_el->appendChild ($impls_node);
|
|
}
|
|
addImplementsElem ($prop, $impl_node);
|
|
if ($iface =~ /(\w+)_TYPE_(\w+)/) {
|
|
$impl_elem = $doc->createElement('interface');
|
|
$name = StudlyCaps (lc ("$1_$2"));
|
|
$impl_elem->setAttribute ("cname", "$name");
|
|
$impls_node->appendChild($impl_elem);
|
|
}
|
|
$typefunc =~ s/G_IMPLEMENT_INTERFACE\s*\(.*?\)//;
|
|
}
|
|
}
|
|
|
|
sub parseTypeFunc
|
|
{
|
|
my ($obj_el, $typefunc) = @_;
|
|
|
|
my @type_lines = split (/\n/, $typefunc);
|
|
|
|
my $linenum = 0;
|
|
$impl_node = undef;
|
|
while ($linenum < @type_lines) {
|
|
|
|
my $line = $type_lines[$linenum];
|
|
|
|
if ($line =~ /#define/) {
|
|
# FIXME: This ignores the bool helper macro thingie.
|
|
} elsif ($line =~ /g_type_add_interface_static/) {
|
|
my $prop = $line;
|
|
do {
|
|
$prop .= $type_lines[++$linenum];
|
|
} until ($type_lines[$linenum] =~ /;/);
|
|
if (not $impl_node) {
|
|
$impl_node = $doc->createElement ("implements");
|
|
$obj_el->appendChild ($impl_node);
|
|
}
|
|
addImplementsElem ($prop, $impl_node);
|
|
}
|
|
$linenum++;
|
|
}
|
|
}
|
|
|
|
##############################################################
|
|
# Converts a dash or underscore separated name to StudlyCaps.
|
|
##############################################################
|
|
|
|
sub StudlyCaps
|
|
{
|
|
my ($symb) = @_;
|
|
$symb =~ s/^([a-z])/\u\1/;
|
|
$symb =~ s/^(\d)/\1_/;
|
|
$symb =~ s/[-_]([a-z])/\u\1/g;
|
|
$symb =~ s/[-_](\d)/\1/g;
|
|
$symb =~ s/^2/Two/;
|
|
$symb =~ s/^3/Three/;
|
|
return $symb;
|
|
}
|
|
|