#!/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 = ){ $localHeader .= $ln; } close HEADFILE; } if ($OUTPUTFORLOCAL){ open FOOTFILE, "$SRCDIR/xpcomfoot.txt"; while($ln = ){ $localFooter .= $ln; } close FOOTFILE; } # printInnerInterfacesList(); loadObjectMap(); if (! -e "$OUTPUTDIR/objref") { mkdir "$OUTPUTDIR/objref"; } if (! -e "$OUTPUTDIR/ifaces") { mkdir "$OUTPUTDIR/ifaces"; } if (! -e "$OUTPUTDIR/comps") { mkdir "$OUTPUTDIR/comps"; } if ($GENERATE_INDEX){ generateMainIndex(); } parseComponents(); if ($PARSE_INTERFACES){ chdir $IDLDIR; if ($PARSE_IDL){ parseIDLFiles(); } my $fl; while ($fl = <*.html>) { if (($fl !~ /^rpI/) && ($fl !~ /xpctest/)){ push(@filesToParse,$fl); } } generateCrossIndex(); print "Outputting interface descriptions...\n"; for (my $tidx = 0; $tidx; while ($ln =~ /^\s+$/){ $ln = ; } INFILEITER: while ($ln){ %keys = (); @consts = (); %attributes = (); %methods = (); $interfacename = ""; my $comment = parseComment($ln); if ($comment){ $ln = ; if ($ln =~ /\/\*/){ my $ctmp = $keys{'comment'}; $comment = parseComment($ln); $keys{'comment'} = $ctmp . $keys{'comment'}; $ln = ; } } my $interface = parseInterface($ln); if ($interface){ if ($keys{"status"} =~ /FROZEN/i){ $frozenInterfaces{$interfacename} = $interfacename; } if (!$comment){ $comment = parseComment($ln); } if (!$allInterfaces{$interfacename}){ $changesLog .= "ADDED: $interfacename \n"; } $interfaceFiles{$interfacename} = $filesToParse[$tidx]; } print $filesToParse[$tidx] . " - " . $keys{'name'} . "\n"; open OUTFILE, ">$OUTPUTDIR/ifaces/" . $keys{'name'} . ".html"; print OUTFILE getHeader("Interface Reference - $interfacename","xpcomref","xpcomref", "../"); outputInterface(); MEMBERSITER: while ($ln = ){ # if ($ln == undef){ last INFILEITER; } if ($ln =~ /^\s+$/){ next MEMBERSITER; } my $comment = parseComment($ln); if ($comment){ $ln = ; if ($ln =~ /\/\*/){ parseComment($ln); $ln = ; } } if ($ln =~ /^interface/){ delete $allInterfaces{$interfacename}; next INFILEITER; } if ($ln =~ /^const/){ parseConst($ln); } elsif ($ln =~ /^attribute/){ parseAttribute($ln); } elsif ($ln =~ /^method/){ parseMethod($ln,0); } %keys=(); } } continue { if (scalar @consts){ outputConsts(0,0); } if (scalar keys %attributes){ outputAttributes(0,0); } if (scalar keys %methods){ outputMethods(0); } outputCrossRefs($interfacename); print OUTFILE getFooter("../"); close OUTFILE; } delete $allInterfaces{$interfacename}; close INFILE; } outputFrozenInterfaces(); } foreach $iface (keys %allInterfaces) { print "MISSING: " . $iface . "\n"; } if ($PARSE_COMPONENTS){ outputComponents(); } print "Maximum Interface length is $maxifacelength\n"; print "Maximum Name length is $maxnamelength\n"; print "Maximum Description length is $maxdesclength\n"; system ("cp $SRCDIR/index.html $OUTPUTDIR"); system ("cp $SRCDIR/creatingcomps.html $OUTPUTDIR"); system ("cp $SRCDIR/scriptables.html $OUTPUTDIR/objref/index.html"); print $changesLog; chdir $SRCDIR; sub parseIDLFiles { print "Parsing idl files...\n"; my $fl; while ($fl = <*.idl>) { if (-e "$OVERRIDEIDLDIR/$fl"){ system ("$XPIDL -m doc $OVERRIDEIDLDIR/$fl"); } else { system ("$XPIDL -m doc $fl"); } } } sub loadObjectMap { open OBJMAP, "objmap.txt" or die $!; my $ln; while ($ln = ){ $ln =~ /^(.*)\->(.*)\s*$/; $interfaceObjectMap{$1}=$2; } close OBJMAP; } sub convertType { my $type, $rest; my $typespec = $_[0]; my $makelink = $_[1]; my $objname = $_[2]; $typespec =~ s/\&//; $typespec =~ s/Star(\*?)$/$1/; $typespec =~ s/\s\*/*/; $typespecmod = $typespec; $typespecmod =~ s/\s|\*//g; if ($objname && $interfaceObjectMap{$typespecmod}){ $typespec = $interfaceObjectMap{$typespecmod}; if ($makelink && (index($typespecmod,"nsI") == 0) && ($typespec ne $objname)){ my $path = ""; # if ($makelink == 2){ $path = "$XPCOMREFURL/ifaces/"; } $typespec = "$typespec"; } } else { if ($typespec =~ /nsIID/){ $typespec =~ s/\*//; $makelink=0; } if ($typespec =~ /((nsI|inI|ipcI)[A-Za-z0-9_]*)(\s*.*)/){ $type=$1; $rest=$3; $rest =~ s/\s*\*//; my $path = ""; if ($objname || ($makelink == 2)){ $path = "$XPCOMREFURL/ifaces/"; } if ($makelink && ($type ne $interfacename)){ $typespec = "$type$rest"; } else { $typespec = $type . $rest; } } } return $typespec; } sub convertArgName { my $argname = $_[0]; if (!($argname =~ s/a([A-Z])([a-z])/\l$1$2/)){ $argname =~ s/a([A-Z])([A-Z])/$1$2/; } return $argname; } sub parseInterface { my $ln = $_[0]; if ($ln =~ /interface\s*(noscript)*\s*([A-Za-z0-9_]*)/){ $keys{"noscript"} = $1; $keys{"name"} = $2; $interfacename = $2; if ($ln = ){ if ($ln =~ /iid\s*(.*)$/){ $keys{"iid"} = $1; } } if ($ln = ){ if ($ln =~ /inheritsfrom\s*(.*)$/){ $keys{"inheritsInterface"} = $1; $keys{"inherits"} = convertType($1,1,0); } } return 1; } else { return 0; } } sub parseConst { my $ln = $_[0]; my $val=""; $ln =~ s/^const\s*//; if ($ln =~ s/\s=\s(.*)$//){ $val = "= $1"; } $ln =~ s/([A-Za-z0-9_]*)$//; chomp $ln; push @consts, [$1 , $ln, $keys{'comment'}, $val, $interfacename]; } sub parseAttribute { my $ln = $_[0]; my $readonly=0, $notxpcom=0, $noscript=0; $ln =~ s/^attribute\s*//; if ($ln =~ s/^readonly\s*//){ $readonly=1; } if ($ln =~ s/^notxpcom\s*//){ $notxpcom=1; } if ($ln =~ s/^unscriptable\s*//){ $noscript=1; } $ln =~ s/([A-Za-z0-9_]*)$//; chomp $ln; if ($readonly){ $attributes{$1 . ":readonly"} = 1; } $attributes{$1} = $ln; $attributes{$1 . ":comment"} = $keys{'comment'}; $attributes{$1 . ":interface"} = $interfacename; my $extra = ""; if ($notxpcom){ $extra .= "[notxpcom] "; } if ($noscript){ $extra .= "[noscript] "; } $attributes{$1 . ":extraflags"} = $extra; } sub parseMethod { my $ln = $_[0]; my $objname = $_[1]; my $unscriptable = ($ln =~ /unscriptable/); $ln =~ /([A-Za-z0-9_]*)$/; my $name = $1; $methods{$name} = $keys{'comment'}; $methods{$name . ':unscriptable'} = $unscriptable; $methods{$name . ':interface'} = $interfacename; my $argspec; my @args; my @argsdesc; while ($ln = ){ if ($ln =~ /^\s+$/){ last; } if ($ln =~ s/^\s*argument\s*([inout]*(retval)*)\s*//){ chomp $ln; if ($argspec){ $argspec .= " , "; } if ($1 eq "outretval"){ $argspec .= "retval "; } elsif ($1 ne "in"){ $argspec .= "$1 "; } $ln =~ /^(.*)\s+([A-Za-z0-9_]*)$/; $argname = convertArgName($2); $argspec .= convertType($1,1,$objname) . " " . $argname; push @args, $argname; if ($keys{"param:" . $argname}){ $methods{$name . ":argsdesc:" . $argname} = "$argname: " . $keys{"param:" . $argname}; } } elsif ($ln =~ s/^\s*returns\s*//){ $ln =~ s/\s//g; $methods{$name . ":returns"} = $ln; if ($keys{'return'}){ $methods{$name . ":returnsdesc"} = $keys{'return'}; } } elsif ($ln =~ s/^\s*notxpcom\s*//){ $methods{$name . ":extraflags"} .= "[notxpcom]"; } } if (scalar @args){ $methods{$name . ":args"} = \@args; $methods{$name . ":argspec"} = $argspec; } } sub parseComment { my $ln = $_[0]; my $multikey=""; $keys{"comment"} = ""; if ($ln !~ /\/\*/){ return 0; } ITER: while ($ln) { if ($ln =~ /\*\//){ if ($interfacename !~ /^nsIUR[IL]$/){ $keys{'comment'} =~ s/(http\:[^\s]*)\s/$1<\/a>\n/g; } $keys{'comment'} =~ s/

([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 = ; } $keys{'comment'} =~ s/(http[^\s]*)\s/$1<\/a>\n/g; $keys{'comment'} =~ s/

([a-z])/

\u$1/g; if ($keys{'comment'} !~ /^nsI/){ $keys{'comment'} =~ s/^([a-z])/\u$1/; } return 1; } sub outputInterface { my $ioutput = "

" . $keys{'name'} . "

\n\n"; $ioutput .= "
\n"; $ioutput .= "\n"; if ($keys{'iid'}){ $ioutput .= " \n"; } if ($keys{'module'}){ $ioutput .= " \n"; } if ($keys{'inherits'}){ $ioutput .= " \n"; } if ($keys{'name'} eq "nsISupports"){ $keys{'status'} = "FROZEN"; } if ($dirsToParseIdx == 1){ $ioutput .= " "; $ioutput .= "\n"; } elsif ($keys{'status'}){ $ioutput .= " \n"; } if (index($allInterfaces{$interfacename},"~") != -1){ $ioutput .= " \n"; } $ioutput .= "
IID:" . $keys{'iid'} . "
Group:" . $keys{'module'} . "
Inherits From:" . $keys{'inherits'} . "
Status:This interface has been removed from newer versions
Status:" . $keys{'status'} . "
Added:New since Mozilla 1.7
\n\n"; if ($keys{'scriptable'}){ $ioutput .= "

This interface is not scriptable.

\n"; } $keys{'comment'} =~ s/^$keys{'name'}\s*\n//i; $keys{'comment'} =~ s/^<\/p>

//; $keys{'comment'} =~ s//<param>/g; if ($keys{'comment'}){ if (($keys{'name'} eq "nsIURI") || ($keys{'name'} eq "nsIURL")){ $ioutput .= "

\n" . $keys{'comment'} . "

\n\n"; } else { $ioutput .= "

\n" . $keys{'comment'} . "

\n\n"; } } my $creationDetail = $interfaceCreationMap{$keys{'name'}}; if ($creationDetail =~ /SERVICE\s*(.*)$/) { my $compname = $1; $ioutput .= "

This interface is intended to be used as a service."; if ($compname) { $ioutput .= " To create an object implementing this interface:\n"; $ioutput .= "

var obj = Components.classes[\"$compname\"].\n" ;
      $ioutput .= "            getService(Components.interfaces." . $keys{'name'} . ");
"; } else { $ioutput .= "

"; } } elsif ($creationDetail =~ /INSTANCE\s*(.*)$/) { my $compname = $1; $ioutput .= "

This interface is intended to be used as an instance."; if ($compname) { $ioutput .= " To create an object implementing this interface:\n"; $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 .= "

An object of this interface must be created in the following way:

"; $ioutput .= "
$1
\n" ; } } elsif ($creationDetail =~ /OTHER\s*(.*)$/) { my $compname = $1; if ($compname) { $ioutput .= "

An object of this interface should be created in the following way:

"; $ioutput .= "
$1
\n" ; } } if ($components{$keys{'name'}}){ $ioutput .= "

This interface is implemented by the following components:

\n\n
    \n"; $ioutput .= $components{$keys{'name'}} . "
\n\n"; } $ioutput .= "
\n\n
\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/