#!/usr/bin/perl
# TODO:
# - add non-int constant values
# - interface names referenced in classes should be modified to be classes, and/or point to
# interfaces directory
# - interfaces in methods in classes need to always be links regardless of source interface name
# - c_download1.html has an iframe in its content
# Set $OUTPUTFORLOCAL to 1 to output for local filesystem. This is useful when
# debugging because links are not absolute
# The follwing files are used by this script:
# xpcomhead.txt - page header (for local output only)
# xpcomfoot.txt - page footer (for local output only)
# objmap.txt - mapping of Mozilla types to more common names (such as PRBool to boolean)
# groups.txt - list of all interfaces organized into groups
# ctoi.txt - list of components and which interfaces they implement
# index.html - index page, copied to output directory
# creatingcomps.html - page about creating components
# scriptables.html - index page for the object references, copied to $OUTPUTDIR/objref/index.html
# flags may be disabled to only perform certain steps, useful when debugging this script
my $PARSE_IDL = 1;
my $PARSE_INTERFACES = 1;
my $PARSE_COMPONENTS = 1;
my $GENERATE_INDEX = 1;
my $OUTPUTFORLOCAL = 0;
# path to xpidl
my $XPIDL = "/builds/trunk-working/mozilla/output/dist/bin/xpidl";
# working source directory (the directory that this script is in)
my $SRCDIR = "/xulplanet/xultu/xpcom";
# pointer to a directory that will store object reference links. I don't think this
# is really used.
my $ELEMREFQUICKDIR = "/xulplanet/xultu/xpcom/elemrefquick";
# directory where idl files are
my $IDLDIR = "/builds/trunk-working/mozilla/output/dist/idl";
# override directory. IDL files in here will override those in $IDLDIR
my $OVERRIDEIDLDIR = "/xulplanet/xultu/xpcom/overrideidl";
# output directory, must already exist
my $OUTPUTDIR = "/xulplanet/xultu/output/xpcomref";
my $XPCOMREFURL ="http://www.xulplanet.com/references/xpcomref";
my $OBJREFURL ="http://www.xulplanet.com/references/objref";
my %allInterfaces;
my %interfaceFiles;
my %frozenInterfaces;
my %usedInterfaceList;
my %interfaceObjectMap;
my %interfaceCreationMap;
my %crossRefMap;
my @filesToParse = ();
my %groups;
my %groupData;
my %components;
my $interfacename;
my %keys;
my @consts;
my %attributes;
my %methods;
my %allNamesForInterface;
my $localHeader = "", $localFooter = "";
my $maxifacelength = 0;
my $maxnamelength = 0;
my $maxdesclength = 0;
if ($OUTPUTFORLOCAL){
open HEADFILE, "$SRCDIR/xpcomhead.txt";
while($ln = ([a-z])/ \u$1/g;
if ($keys{'comment'} !~ /^nsI/){
$keys{'comment'} =~ s/^([a-z])/\u$1/;
}
return 1;
}
$ln =~ s/^[\/\*\s]*//;
if ((length $ln) == 0){
if ($keys{"comment"}){ $keys{"comment"} .= " "; }
$multikey="";
}
if ($multikey){
if ($ln =~ /\@[A-Za-z0-9_]/){
$multikey="";
}
else {
$keys{$multikey} .= " " . $ln;
next ITER;
}
}
if ($ln =~ /^\@([A-Za-z]*)\s*(.*)$/){
my $key = lc($1);
if ($key eq "param"){
$2 =~ /^([A-Za-z0-9_]*)\s*(.*)$/;
$multikey="param:" . convertArgName($1);
$keys{$multikey} = $2;
}
else {
$multikey=$key;
$keys{$key} = $2;
}
}
else {
$ln =~ s/\|//g;
$keys{"comment"} .= $ln;
}
}
continue { $ln = ([a-z])/ \u$1/g;
if ($keys{'comment'} !~ /^nsI/){
$keys{'comment'} =~ s/^([a-z])/\u$1/;
}
return 1;
}
sub outputInterface
{
my $ioutput = " This interface is not scriptable. //;
$keys{'comment'} =~ s//<param>/g;
if ($keys{'comment'}){
if (($keys{'name'} eq "nsIURI") || ($keys{'name'} eq "nsIURL")){
$ioutput .= " \n" . $keys{'comment'} . " \n" . $keys{'comment'} . " This interface is intended to be used as a service.";
if ($compname) {
$ioutput .= " To create an object implementing this interface:\n";
$ioutput .= " This interface is intended to be used as an instance.";
if ($compname) {
$ioutput .= " To create an object implementing this interface:\n";
$ioutput .= " An object of this interface must be created in the following way: An object of this interface should be created in the following way: This interface is implemented by the following components: \n";
if ($attributes{$attribute . ":extraflags"}){ print OUTFILE $attributes{$attribute . ":extraflags"} };
if ($attributes{$attribute . ':readonly'}){ print OUTFILE "readonly "; }
print OUTFILE " " . convertType($attributes{$attribute},2,$objname) . " ";
if ($showInterfaces){ print OUTFILE $attributes{$attribute . ':interface'} . "."; }
print OUTFILE "$attribute\n \n" . $attributes{$attribute . ':comment'} . " \n";
foreach $method (sort { uc($a) cmp uc($b) } keys %methods){
if ($method !~ /\:/){
print OUTFILE " \n";
print OUTFILE " \n";
if ($methods{$method . 'unscriptable'}){ print OUTFILE "[noscript]"; };
if ($methods{$method . ":extraflags"}){ print OUTFILE $methods{$method . ":extraflags"} };
print OUTFILE " " . convertType($methods{$method . ':returns'},1,$objname);
print OUTFILE " $method";
print OUTFILE " ( " . $methods{$method . ':argspec'} . " )\n";
print OUTFILE " //;
$methods{$method} =~ s/([\s\|\[])a([A-Z])([A-Za-z])/$1\l$2$3/g; # convert aValue -> value
print OUTFILE " \n" . $methods{$method} . " \n" .
"The following are all of the frozen interfaces. Frozen " .
"interfaces are those that are stable and are not going " .
"to change.\n" .
" \n";
foreach $iface (sort keys %frozenInterfaces){
print FROZEN "$iface This interface is the type of the following properties: \n";
}
elsif ($type eq "p"){
print OUTFILE "\n This interface is passed as an argument to the following methods: \n";
}
elsif ($type eq "r"){
print OUTFILE "\n This interface is returned from the following methods: \n";
}
}
my $typemod = "method_";
if (type eq "a"){ $typemod = "prop_"; }
if ($hasitem){ print OUTFILE ",\n"; }
print OUTFILE "$ifacename.$pmname";
$hasanyitem = 1;
$hasitem = 1;
}
}
if ($hasitem) {
print OUTFILE " \n"; }
} else { $cmode=0; }
$grouptextbody .= "$interface" . $keys{'name'} . "
\n\n";
$ioutput .= "\n";
if ($keys{'iid'}){ $ioutput .= "
\n\n";
if ($keys{'scriptable'}){
$ioutput .= " \n"; }
if ($keys{'module'}){ $ioutput .= " IID: " . $keys{'iid'} . " \n"; }
if ($keys{'inherits'}){
$ioutput .= " Group: " . $keys{'module'} . " \n";
}
if ($keys{'name'} eq "nsISupports"){ $keys{'status'} = "FROZEN"; }
if ($dirsToParseIdx == 1){
$ioutput .= " Inherits From: " . $keys{'inherits'} . " \n";
}
elsif ($keys{'status'}){
$ioutput .= " Status: ";
$ioutput .= "This interface has been removed from newer versions \n";
}
if (index($allInterfaces{$interfacename},"~") != -1){
$ioutput .= " Status: " . $keys{'status'} . " \n";
}
$ioutput .= "Added: New since Mozilla 1.7 var obj = Components.classes[\"$compname\"].\n" ;
$ioutput .= " getService(Components.interfaces." . $keys{'name'} . ");";
}
else { $ioutput .= ""; }
}
elsif ($creationDetail =~ /INSTANCE\s*(.*)$/) {
my $compname = $1;
$ioutput .= "var obj = Components.classes[\"$compname\"].\n" ;
$ioutput .= " createInstance(Components.interfaces." . $keys{'name'} . ");";
}
else { $ioutput .= ""; }
}
elsif ($creationDetail =~ /OTHERSTRONG\s*(.*)$/) {
my $compname = $1;
if ($compname) {
$ioutput .= "$1
\n" ;
}
}
elsif ($creationDetail =~ /OTHER\s*(.*)$/) {
my $compname = $1;
if ($compname) {
$ioutput .= "$1
\n" ;
}
}
if ($components{$keys{'name'}}){
$ioutput .= "\n";
$ioutput .= $components{$keys{'name'}} . "
\n\n";
}
$ioutput .= "
\n\n";
print OUTFILE $ioutput;
}
sub outputConsts
{
my $showInterfaces = $_[0];
my $objname = $_[1];
print OUTFILE "Constants
\n\n";
print OUTFILE "\n";
foreach $constarr (@consts){
my $cmtext = @{$constarr}[2];
$cmtext =~ s/
\n\n";
}
sub outputAttributes
{
my $showInterfaces = $_[0];
my $objname = $_[1];
if (((scalar @consts) > 0) && ((scalar keys %attributes) > 0)){ print OUTFILE "
\n\n"; }
print OUTFILE "Properties
\n\n";
foreach $attribute (sort { uc($a) cmp uc($b) } keys %attributes){
if ($attribute !~ /\:/){
print OUTFILE "\n";
print OUTFILE "
\n\n";
}
print OUTFILE "Methods
\n\n";
print OUTFILE "\n";
if ($methods{$method . ":unscriptable"}){ print OUTFILE "[noscript]"; };
if ($methods{$method . ":extraflags"}){ print OUTFILE $methods{$method . ":extraflags"} };
print OUTFILE " " . convertType($methods{$method . ':returns'},0,$objname) . " ";
print OUTFILE "" . $method . "";
print OUTFILE " ( " . $methods{$method . ':argspec'} . " )\n";
print OUTFILE " \n";
}
}
print OUTFILE "
\n\n"; }
$hasmethod = 1 ;
print OUTFILE "\n";
if ($methods{$method . ':args'}){
print OUTFILE "
\n";
}
print OUTFILE "Methods
\n\n";
print OUTFILE "\n";
print OUTFILE "
\n\n";
}
sub outputFrozenInterfaces
{
open FROZEN, ">$OUTPUTDIR/" . "frozen.html";
$frozenInterfaces{"nsISupports"} = "nsISupports";
print FROZEN getHeader("Frozen Interfaces","xpcomref","xpcomref", "");
print FROZEN " \n";
print OUTFILE "\n";
foreach $method (sort { uc($a) cmp uc($b) } keys %methods){
if ($method !~ /\:/){
my $ifacename = $methods{$method . ':interface'};
print OUTFILE " Interface Method \n";
}
}
print OUTFILE "\n";
print OUTFILE "" . $methods{$method . ':interface'} . " \n";
if ($methods{$method . ":unscriptable"}){ print OUTFILE "[noscript]"; };
if ($methods{$method . ":extraflags"}){ print OUTFILE $methods{$method . ":extraflags"} };
print OUTFILE " " . convertType($methods{$method . ':returns'},0,$objname) . " ";
print OUTFILE "" .
$method . "";
my $argspec = $methods{$method . ':argspec'};
$argspec =~ s/Frozen Interfaces
\n\n";
print FROZEN "
\n";
}
print FROZEN "
\n\n";
}
print OUTFILE "\n\nReferences
\n";
}
if (!$hasitem){
if ($type eq "a"){
print OUTFILE "\n
\n";
}
%interfaces=();
if ($groupname){
if ($grouptexthead =~ //){ $grouptexthead .= "
"; }
open GROUPSET, ">$OUTPUTDIR/" . "group_$groupnamemod.html";
print GROUPSET getHeader($groupname,"xpcomref","xpcomref", "");
print GROUPSET $grouptexthead . $grouptextbody . getFooter("");
close GROUPSET;
}
$groupname=$1;
$groups{$groupname}="";
$subgroups=0;
$groupnamemod = $groupname;
$groupnamemod =~ s/\s//g;
$grouptextbody = "";
$grouptexthead = "$groupname
\n\n";
}
elsif ($ln =~ /^\((.*)\)/){
$cmode=-1;
foreach $interface (sort sortNames keys %interfaces){
if (substr($interface,0,1) eq "\@"){
if (!$cmode){ $cmode=1; $grouptextbody .= "
\n"; }
} else { $cmode=0; }
my $isfrozen = ($frozenInterfaces{$interface} ? "*" : "");
$grouptextbody .= "$interface
\n";
}
%interfaces=();
my $grouptext = $1;
my $grouptextmod = $1;
$grouptextmod =~ s/\s//g;
if (!$subgroups){
$subgroups=1;
$grouptexthead .= "
Jump to:
\n\n"; }
} else { $cmode=0; }
$grouptextbody .= "$interface
\n";
}
%interfaces=();
if ($grouptextbody){ $grouptextbody .= $ln; }
else { $grouptexthead .= $ln; }
}
elsif ($ln && $ln !~ /^\s+$/){
my $iface = $ln;
$iface =~ s/~//;
if ($ln =~ s/^(.*)\s+\->\s*(.*)//){
$iface = $1;
$interfaceCreationMap{$1} = $2;
}
if (substr($iface,0,1) ne "\@"){
$allInterfaces{$iface} = $iface;
}
$interfaces{$iface} = convertComponentName($iface,0);
}
}
close GROUPS;
$cmode=-1;
foreach $interface (sort sortNames keys %interfaces){
if (substr($interface,0,1) eq "\@"){
if (!$cmode){ $cmode=1; $grouptextbody .= "
\n"; }
} else { $cmode=0; }
$grouptextbody .= "$interface
\n";
}
if ($grouptexthead =~ /
This is a scriptable interface corresponding to "; if ((scalar @interfaceNames) == 1){ my $iname = $interfaceNames[0]; print OUTFILE "the $iname XPCOM interface.
\n\n"; foreach $iface (sort keys %interfacelist){ getInterfaceFileForCombining($iface,$isfirst,($isclass ? $cname : "")); $isfirst = 0; } } elsif ((scalar @interfaceNames) > 1){ print OUTFILE "the following XPCOM interfaces:\n\nThis object is available to unprivileged JavaScript. " . "It implements the following interfaces:
\n\n"; } else { if ((scalar @interfaceNames) > 0){ print OUTFILE "This component implements the following interfaces:
\n\n"; } } print OUTFILE "Reference documentation is generated from " . "Mozilla's source.
\n\n"; if ($OUTPUTFORLOCAL){ return $retval . $localFooter; } return $retval . "\n" . "\n"; } sub getInterfaceFileForCombining { $interfacename = $_[0]; my $isfirst = $_[1]; my $objname = $_[2]; my $inheritsfrom = ""; if ($isfirst){ %keys = (); @consts = (); %attributes = (); %methods = (); } if (($interfacename eq "nsISupports") || ($interfacename eq "nsIClassInfo") || ($usedInterfaceList{$interfacename})){ return; } $usedInterfaceList{$interfacename} = $interfacename; my $ifacefilename = $interfaceFiles{$interfacename}; if (!$ifacefilename){ $ifacefilename = $interfacename . ".html"; } open INFILE, $IDLDIR . "/" . $ifacefilename; my $ln =