#! /usr/bin/perl -w # # Script name: gatherHeaderDoc # Synopsis: Finds all HeaderDoc generated docs in an input # folder and creates a top-level HTML page to them # # Last Updated: $Date: 2009/04/17 23:21:58 $ # # Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved. # # @APPLE_LICENSE_HEADER_START@ # # This file contains Original Code and/or Modifications of Original Code # as defined in and that are subject to the Apple Public Source License # Version 2.0 (the 'License'). You may not use this file except in # compliance with the License. Please obtain a copy of the License at # http://www.opensource.apple.com/apsl/ and read it before using this # file. # # The Original Code and all software distributed under the License are # distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER # EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, # INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. # Please see the License for the specific language governing rights and # limitations under the License. # # @APPLE_LICENSE_HEADER_END@ # # $Revision: 1.18 $ ###################################################################### my $pathSeparator; my $isMacOS; my $uninstalledModulesPath; my $has_resolver; sub resolveLinks($$$); BEGIN { use FindBin qw ($Bin); if ($^O =~ /MacOS/i) { $pathSeparator = ":"; $isMacOS = 1; #$Bin seems to return a colon after the path on certain versions of MacPerl #if it's there we take it out. If not, leave it be #WD-rpw 05/09/02 ($uninstalledModulesPath = $FindBin::Bin) =~ s/([^:]*):$/$1/; } else { $pathSeparator = "/"; $isMacOS = 0; } $uninstalledModulesPath = "$FindBin::Bin"."$pathSeparator"."Modules"; $HeaderDoc::use_styles = 0; } use strict; # use Cwd; use File::Basename; use File::Find; use File::Copy; # use Carp qw(cluck); use lib $uninstalledModulesPath; use POSIX; my $skipTOC = 0; my $generateDocSet = 0; $has_resolver = 1; eval "use HeaderDoc::LinkResolver qw (resolveLinks); 1" || do { $has_resolver = 0; }; # print "HR: $has_resolver\n"; if ($has_resolver) { print "LinkResolver will be used to resolve cross-references.\n"; } # Modules specific to gatherHeaderDoc use HeaderDoc::DocReference; use HeaderDoc::Utilities qw(findRelativePath safeName getAPINameAndDisc printArray printHash updateHashFromConfigFiles getHashFromConfigFile quote resolveLinks sanitize); $HeaderDoc::modulesPath = $INC{'HeaderDoc/Utilities.pm'}; $HeaderDoc::modulesPath =~ s/Utilities.pm$//s; # print "MP: ".$HeaderDoc::modulesPath."\n"; my $debugging = 1; ######################################## Design Overview ################################### # - We scan input directory for frameset files (index.html, by default). # - For each frameset file, we look for a special HTML comment (left by HeaderDoc) # that tell us the name of the header/class and the type (header or cppclass). # - We create a DocReference object to store this info, and also the path to the # frameset file. # - We run through array of DocRef objs and create a master TOC based on the info # - Finally, we visit each TOC file in each frameset and add a "[Top]" link # back to the master TOC. [This is fragile in the current implementation, since # we find TOCs based on searching for a file called "toc.html" in the frameset dir.] # ########################## Get command line arguments and flags ####################### my @inputFiles; my @contentFiles; my $inputDir; my $externalXRefFiles = ""; use Getopt::Std; my %options = (); my %letters_linked = (); my %group_letters_linked = (); getopts("c:dnx:",\%options); # The options are handled after processing config file so they can # override behavior. However, we need to handle the options first # before checking for input file names (which we should do first # to avoid wasting a lot of time before telling the user he/she # did something wrong). my $masterTOCFileName = ""; my $bookxmlname = ""; if (($#ARGV == 0 || $#ARGV == 1 || $#ARGV == 2) && (-d $ARGV[0])) { $inputDir = $ARGV[0]; if ($#ARGV) { $masterTOCFileName = $ARGV[1]; } if ($#ARGV > 1) { $bookxmlname = $ARGV[2]; } } else { die "You must specify a single input directory for processing.\n"; } ########################## Setup from Configuration File ####################### my $localConfigFileName = "headerDoc2HTML.config"; my $preferencesConfigFileName = "com.apple.headerDoc2HTML.config"; my $homeDir; my $usersPreferencesPath; my $systemPreferencesPath; #added WD-rpw 07/30/01 to support running on MacPerl #modified WD-rpw 07/01/02 to support the MacPerl 5.8.0 if ($^O =~ /MacOS/i) { eval { require "FindFolder.pl"; $homeDir = MacPerl::FindFolder("D"); #D = Desktop. Arbitrary place to put things $usersPreferencesPath = MacPerl::FindFolder("P"); #P = Preferences }; if ($@) { import Mac::Files; $homeDir = Mac::Files::FindFolder(kOnSystemDisk(), kDesktopFolderType()); $usersPreferencesPath = Mac::Files::FindFolder(kOnSystemDisk(), kPreferencesFolderType()); } $systemPreferencesPath = $usersPreferencesPath; } else { $homeDir = (getpwuid($<))[7]; $usersPreferencesPath = $homeDir.$pathSeparator."Library".$pathSeparator."Preferences"; $systemPreferencesPath = "/Library/Preferences"; } my $CWD = getcwd(); my @configFiles = ($systemPreferencesPath.$pathSeparator.$preferencesConfigFileName, $usersPreferencesPath.$pathSeparator.$preferencesConfigFileName, $Bin.$pathSeparator.$localConfigFileName, $CWD.$pathSeparator.$localConfigFileName); # ($Bin.$pathSeparator.$localConfigFileName, $usersPreferencesPath.$pathSeparator.$preferencesConfigFileName); # default configuration, which will be modified by assignments found in config files. # The default values listed in this hash must be the same as those in the identical # hash in headerDoc2HTML--so that links between the frameset and the masterTOC work. my %config = ( defaultFrameName => "index.html", masterTOCName => "MasterTOC.html", groupHierLimit => 0, groupHierSubgroupLimit => 0 ); if ($options{c}) { @configFiles = ( $options{c} ); } %config = &updateHashFromConfigFiles(\%config,\@configFiles); my $framesetFileName; my @TOCTemplateList = (); my @TOCNames = (); my $framework = ""; my $frameworknestlevel = -1; my $frameworkShortName = ""; my $frameworkpath = ""; my $frameworkrelated = ""; my $frameworkUID = ""; my $frameworkCopyrightString = ""; my $landingPageUID = ""; my $landingPageFrameworkUID = ""; my $stripDotH = 0; my $gather_functions = 0; my $gather_types = 0; my $gather_properties = 0; my $gather_globals_and_constants = 0; my $gather_man_pages = 0; my $apiUIDPrefix = "apple_ref"; my $compositePageName = "CompositePage.html"; my $classAsComposite = 0; my $externalAPIUIDPrefixes = ""; my %usedInTemplate = (); if (defined $config{"dateFormat"}) { $HeaderDoc::datefmt = $config{"dateFormat"}; if ($HeaderDoc::datefmt !~ /\S/) { $HeaderDoc::datefmt = "%B %d, %Y"; } } else { $HeaderDoc::datefmt = "%B %d, %Y"; } use HeaderDoc::APIOwner; HeaderDoc::APIOwner->fix_date(); my ($sec,$min,$hour,$mday,$mon,$yr,$wday,$yday,$isdst) = localtime(time()); my $yearStamp = strftime("%Y", $sec, $min, $hour, $mday, $mon, $yr, $wday, $yday, $isdst); my $dateStamp = HeaderDoc::HeaderElement::strdate($mon, $mday, $yr + 1900); if (defined $config{"styleImports"}) { $HeaderDoc::styleImports = $config{"styleImports"}; $HeaderDoc::styleImports =~ s/[\n\r]/ /sgo; $HeaderDoc::use_styles = 1; } if (defined $config{"groupHierLimit"}) { $HeaderDoc::groupHierLimit = $config{"groupHierLimit"}; } if (defined $config{"groupHierSubgroupLimit"}) { $HeaderDoc::groupHierSubgroupLimit = $config{"groupHierSubgroupLimit"}; } if (defined $config{"tocStyleImports"}) { $HeaderDoc::tocStyleImports = $config{"tocStyleImports"}; $HeaderDoc::tocStyleImports =~ s/[\n\r]/ /sgo; $HeaderDoc::use_styles = 1; } if (defined $config{"textStyle"}) { HeaderDoc::APIOwner->setStyle("text", $config{"textStyle"}); } if (defined $config{"copyrightOwner"}) { $HeaderDoc::copyrightOwner = $config{"copyrightOwner"}; } if (defined $config{"commentStyle"}) { HeaderDoc::APIOwner->setStyle("comment", $config{"commentStyle"}); } if (defined $config{"preprocessorStyle"}) { HeaderDoc::APIOwner->setStyle("preprocessor", $config{"preprocessorStyle"}); } if (defined $config{"funcNameStyle"}) { HeaderDoc::APIOwner->setStyle("function", $config{"funcNameStyle"}); } if (defined $config{"stringStyle"}) { HeaderDoc::APIOwner->setStyle("string", $config{"stringStyle"}); } if (defined $config{"charStyle"}) { HeaderDoc::APIOwner->setStyle("char", $config{"charStyle"}); } if (defined $config{"numberStyle"}) { HeaderDoc::APIOwner->setStyle("number", $config{"numberStyle"}); } if (defined $config{"keywordStyle"}) { HeaderDoc::APIOwner->setStyle("keyword", $config{"keywordStyle"}); } if (defined $config{"typeStyle"}) { HeaderDoc::APIOwner->setStyle("type", $config{"typeStyle"}); } if (defined $config{"paramStyle"}) { HeaderDoc::APIOwner->setStyle("param", $config{"paramStyle"}); } if (defined $config{"varStyle"}) { HeaderDoc::APIOwner->setStyle("var", $config{"varStyle"}); } if (defined $config{"templateStyle"}) { HeaderDoc::APIOwner->setStyle("template", $config{"templateStyle"}); } if (defined $config{"externalXRefFiles"}) { $externalXRefFiles = $config{"externalXRefFiles"}; } if (defined $config{"externalAPIUIDPrefixes"}) { $externalAPIUIDPrefixes = $config{"externalAPIUIDPrefixes"}; } if (defined $config{"defaultFrameName"}) { $framesetFileName = $config{"defaultFrameName"}; } if (defined $config{"apiUIDPrefix"}) { $apiUIDPrefix = $config{"apiUIDPrefix"}; } if (defined $config{"compositePageName"}) { $compositePageName = $config{"compositePageName"}; } if (defined $config{"classAsComposite"}) { $classAsComposite = $config{"classAsComposite"}; $classAsComposite =~ s/\s*//; } else { $classAsComposite = 0; } if (defined $config{"masterTOCName"} && $masterTOCFileName eq "") { $masterTOCFileName = $config{"masterTOCName"}; } if (defined $config{"stripDotH"}) { $stripDotH = $config{"stripDotH"}; } if (defined $config{"TOCTemplateFile"}) { my $TOCTemplateFile = $config{"TOCTemplateFile"}; my $oldRecSep = $/; undef $/; # read in files as strings my @filelist = split(/\s/, $TOCTemplateFile); foreach my $file (@filelist) { my %used = (); print "Searching for $file\n"; my @templateFiles = ($systemPreferencesPath.$pathSeparator.$file, $usersPreferencesPath.$pathSeparator.$file, $Bin.$pathSeparator.$file, $file); my $TOCTemplate = ""; my $found = 0; my $foundpath = ""; foreach my $filename (@templateFiles) { if (open(TOCFILE, "<$filename")) { $TOCTemplate = ; close(TOCFILE); $found = 1; $foundpath = $filename; } } if (!$found) { die("Template file $file not found.\n"); } else { print "Found at $foundpath\n"; } push(@TOCTemplateList, $TOCTemplate); push(@TOCNames, basename($file)); if ($TOCTemplate =~ /\$\$\s*typelist/) { $gather_types = 1; $used{type} = 1; } if ($TOCTemplate =~ /\$\$\s*proplist/) { $gather_properties = 1; $used{prop} = 1; } if ($TOCTemplate =~ /\$\$\s*datalist/) { $gather_globals_and_constants = 1; $used{data} = 1; } if ($TOCTemplate =~ /\$\$\s*functionlist/) { $gather_functions = 1; $used{function} = 1; } if ($TOCTemplate =~ /\$\$\s*manpagelist/) { $gather_man_pages = 1; $used{manpage} = 1; } if ($TOCTemplate =~ /\$\$\s*headerlist/) { $used{header} = 1; } if ($TOCTemplate =~ /\$\$\s*macrolist/) { $used{macro} = 1; } if ($TOCTemplate =~ /\$\$\s*protocollist/) { $used{protocol} = 1; } if ($TOCTemplate =~ /\$\$\s*categorylist/) { $used{category} = 1; } if ($TOCTemplate =~ /\$\$\s*classlist/) { $used{class} = 1; } if ($TOCTemplate =~ /\$\$\s*comintlist/) { $used{comint} = 1; } $usedInTemplate{$TOCTemplate} = \%used; } $/ = $oldRecSep; } my $useBreadcrumbs = 0; if (defined $config{"useBreadcrumbs"}) { $useBreadcrumbs = $config{"useBreadcrumbs"}; } ########################## Handle command line flags ####################### if ($options{d}) { $generateDocSet = 1; if ($options{n}) { $skipTOC = 1; } } if ($options{x}) { $externalXRefFiles = $options{x}; } ########################## Input Folder and Files ####################### if ($^O =~ /MacOS/i) { find(\&getFiles, $inputDir); $inputDir =~ s/([^:]*):$/$1/; #WD-rpw 07/01/02 } else { $inputDir =~ s|(.*)/$|$1|; # get rid of trailing slash, if any if ($inputDir !~ /^\//) { # not absolute path -- !!! should check for ~ my $cwd = getcwd(); $inputDir = $cwd.$pathSeparator.$inputDir; } &find({wanted => \&getFiles, follow => 1}, $inputDir); } unless (@inputFiles) { print STDERR "No valid input files specified. \n\n"; exit(-1)}; $GHD::bgcolor = "#ffffff"; if (!scalar(@TOCTemplateList)) { my $TOCTemplate = default_template(); push(@TOCTemplateList, $TOCTemplate); push(@TOCNames, "masterTOC.html") } # print "GatherFunc: $gather_functions\n"; # print "TT: $TOCTemplate\n"; sub getFiles { my $filePath = $File::Find::name; my $fileName = $_; my $localDebug = 0; my $basePath = dirname($filePath); my $dirName = basename($basePath); print "$fileName ($filePath): " if ($localDebug); if ($fileName =~ /$framesetFileName/) { print "HTML frameset\n" if ($localDebug); push(@inputFiles, $filePath); push(@contentFiles, $filePath); } elsif ($dirName =~ /^(man|cat)[\w\d]+$/ && $gather_man_pages) { print "Man Page\n" if ($localDebug); push(@inputFiles, $filePath); push(@contentFiles, $filePath); } elsif ($fileName =~ /Constants\.html$/ && $gather_globals_and_constants && !$classAsComposite) { print "Constants\n" if ($localDebug); push(@inputFiles, $filePath); push(@contentFiles, $filePath); } elsif ($fileName =~ /Vars\.html$/ && $gather_globals_and_constants && !$classAsComposite) { print "Vars\n" if ($localDebug); push(@inputFiles, $filePath); push(@contentFiles, $filePath); } elsif ($fileName =~ /DataTypes\.html$/ && $gather_types && !$classAsComposite) { print "DataTypes\n" if ($localDebug); push(@inputFiles, $filePath); push(@contentFiles, $filePath); } elsif ($fileName =~ /Structs\.html$/ && $gather_types && !$classAsComposite) { print "Structs\n" if ($localDebug); push(@inputFiles, $filePath); push(@contentFiles, $filePath); } elsif ($fileName =~ /Enums\.html$/ && $gather_types && !$classAsComposite) { print "Enums\n" if ($localDebug); push(@inputFiles, $filePath); push(@contentFiles, $filePath); } elsif ($fileName =~ /Methods\.html$/ && $gather_functions && !$classAsComposite) { print "Methods\n" if ($localDebug); push(@inputFiles, $filePath); push(@contentFiles, $filePath); } elsif ($fileName =~ /Functions\.html$/ && $gather_functions && !$classAsComposite) { print "Functions\n" if ($localDebug); push(@inputFiles, $filePath); push(@contentFiles, $filePath); } elsif ($fileName =~ /doc\.html$/ && !$classAsComposite) { print "Framework Documentation\n" if ($localDebug); # Framework (maybe) push(@inputFiles, $filePath); push(@contentFiles, $filePath); } elsif ($fileName !~ /toc\.html$/) { print "Other Content\n" if ($localDebug); # Don't push the TOCs. if ($classAsComposite && $fileName =~ /\Q$compositePageName\E$/) { push(@inputFiles, $filePath); } push(@contentFiles, $filePath); } else { print "toc.\n" if ($localDebug); } } ########################## Find HeaderDoc Comments ####################### my @fileRefSets; my @headerFramesetRefs; my @propFramesetRefs; my @dataFramesetRefs; my @macroFramesetRefs; my @typeFramesetRefs; my @comintFramesetRefs; my @classFramesetRefs; my @manpageFramesetRefs; my @categoryFramesetRefs; my @protocolFramesetRefs; my @functionRefs; my $frameworkabstract = ""; my $frameworkdiscussion = ""; my $oldRecSep = $/; undef $/; # read in files as strings my $localDebug = 0; my %groups = (); $groups{" "}=""; $| = 1; print "Processing..."; foreach my $file (@inputFiles) { my @perFileDocRefs = (); if (-f $file) { open (INFILE, "<$file") || die "Can't open $file: $!\n"; my $fileString = ; close INFILE; my $fileStringCopy = $fileString; while ($fileStringCopy =~ s/<\!--\s+(headerDoc\s*=.*?)-->(.*)/$2/s) { my $fullComment = $1; my $tail = $2; my $inDiscussion = 0; my $inAbstract = 0; my $inPath = 0; my $inRelated = 0; my $inFWUID = 0; my $inFWCopyright = 0; my @stockpairs = split(/;/, $fullComment); my @pairs = (); my $temp = ""; foreach my $stockpair (@stockpairs) { if (length($temp)) { $temp .= $stockpair; if ($temp !~ /\\$/) { push(@pairs, $temp); $temp = ""; } } else { if ($stockpair =~ /\\$/) { $temp = $stockpair; $temp =~ s/\\$/;/s; } else { push(@pairs, $stockpair); $temp = ""; } } } my $docRef = HeaderDoc::DocReference->new; $docRef->path($file); # print "PATH: $file\n"; print "."; foreach my $pair (@pairs) { my ($key, $value) = split(/=/, $pair, 2); $key =~ s/^\s+|\s+$//; $value =~ s/^\s+|\s+$//; SWITCH: { ($key =~ /indexgroup/) && do { my $group = $value; $group =~ s/^\s*//sg; $group =~ s/\s*$//sg; $group =~ s/\\;/;/sg; $docRef->group($group); $groups{$group}=1; # print "SAW $group\n"; }; ($key =~ /headerDoc/) && do { $docRef->type($value); if ($value =~ /frameworkdiscussion/) { if (rightframework($file)) { $inDiscussion = 1; } } if ($value =~ /frameworkabstract/) { if (rightframework($file)) { $inAbstract = 1; } } if ($value =~ /frameworkpath/) { if (rightframework($file)) { $inPath = 1; } } if ($value =~ /frameworkrelated/) { if (rightframework($file)) { $inRelated = 1; } } if ($value =~ /frameworkuid/) { # print "FWUID DETECTED ($value)\n"; if (rightframework($file)) { $inFWUID = 1; # print "RIGHT FILE\n"; # $frameworkUID = $value; # $frameworkUID =~ s/^\s*//sg; # $frameworkUID =~ s/\s*$//sg; } }; if ($value =~ /frameworkcopyright/) { # print "FWCopyright DETECTED ($value)\n"; if (rightframework($file)) { $inFWCopyright = 1; # print "RIGHT FILE\n"; # $frameworkUID = $value; # $frameworkUID =~ s/^\s*//sg; # $frameworkUID =~ s/\s*$//sg; } }; last SWITCH; }; ($key =~ /shortname/) && do { $docRef->shortname($value); last SWITCH; }; ($key =~ /uid/) && do { $docRef->uid($value); }; ($key =~ /name/) && do { $docRef->name($value); if ($inDiscussion && $value =~ /start/) { $frameworkdiscussion = $tail; $frameworkdiscussion =~ s/ '$tocFile' doesn't exist!\n"; print "Cannot add [top] link for frameset doc reference:\n"; print " name: $name\n"; print " type: $type\n"; print " path: $path\n"; } } if ($useBreadcrumbs) { foreach my $file (@contentFiles) { # print "FILE: $file\n"; if (-e "$file" && ! -d "$file" ) { my $oldRecSep = $/; undef $/; # read in file as string open(INFILE, "<$file") || die "Can't read file $file.\n"; my $fileString = ; close INFILE; $/ = $oldRecSep; my $uniqueMarker = "headerDoc=\"topLink\""; # if ($fileString !~ /$uniqueMarker/) { # we haven't been here before if (length($framework)) { my $relPathToMasterTOC = &findRelativePath($file, $masterTOC); my $breadcrumb = "$framework"; $fileString =~ s/.*?/$breadcrumb/i; open (OUTFILE, ">$file") || die "Can't write file $file.\n"; print OUTFILE $fileString; close (OUTFILE); } else { warn "No framework (.hdoc) file found and breadcrumb specified. Breadcrumbs will\nnot be inserted.\n"; } # } } } } } sub getLinkToFramesetFrom { my $masterTOCFile = shift; my $dest = shift; my $name = shift; my $group = shift; my $typename = shift; my $linkString; my $relPath = &findRelativePath($masterTOCFile, $dest); my $namestring = getNameStringForLink($name, $group, $typename); $linkString = "$name
\n"; return $linkString; } sub getNameStringForLink { my $name = shift; my $group = shift; my $typename = shift; my $namestring = ""; my $groupns = $group; $groupns =~ s/\s/_/sg; my $grouptype = $groupns."_".$typename; my $firsttwo = uc($name); $firsttwo =~ s/^(..).*$/$1/s; # print "FIRSTTWO: $firsttwo\n"; # cluck("test\n"); if (!$letters_linked{$firsttwo}) { $namestring = "name=\"group_$grouptype"."_$firsttwo\""; $letters_linked{$firsttwo} = 1; # print "SET letters_linked{$firsttwo}\n"; } else { $letters_linked{$firsttwo}++; } return $namestring; } sub getLinkToFunctionFrom { my $masterTOCFile = shift; my $dest = shift; my $name = shift; my $uid = shift; my $group = shift; my $typename = shift; my $linkString; my $relPath = &findRelativePath($masterTOCFile, $dest); my $ns = getNameStringForLink($name, $group, $typename); my $noClassName = $name; $noClassName =~ s/.*\:\://s; my $urlname = sanitize($noClassName); my $lp = ""; if ($uid && length($uid)) { $urlname = $uid; $lp = " logicalPath=\"$uid\""; } # print "UIDCHECK: $uid\n"; if ($uid =~ /\/\/apple_ref\/occ\/(clm|instm|intfcm|intfm)\//) { # Format Objective-C class name my $type = $1; $name =~ s/^(.*)\:\://; my $class = $1; my $plusmin = "+"; if ($type eq "instm") { $plusmin = "-"; } $name = $plusmin."[ $class $name ]"; } $linkString = "$name
\n"; return $linkString; } sub objName { # for sorting objects by their names uc($a->name()) cmp uc($b->name()); } sub default_template { my $template = "\n"; my $stylesheet = ""; # my $he = HeaderElement::new; # my $stylesheet = $he->styleSheet(0); $template .= "\n\n \$\$title\@\@\n \n\n$stylesheet\n

\$\$framework\@\@ Documentation



\n"; $template .= "

\$\$frameworkdiscussion\@\@

"; $template .= "\$\$headersection\@\@

Headers

\n
\n\$\$headerlist cols=2 order=down atts=border=\"0\" width=\"80%\"\@\@\n
\$\$/headersection\@\@\n"; $template .= "\$\$classsection\@\@

Classes

\n
\n\$\$classlist cols=2 order=down atts=border=\"0\" width=\"80%\"\@\@\n
\$\$/classsection\@\@\n"; $template .= "\$\$categorysection\@\@

Categories

\n
\n\$\$categorylist cols=2 order=down atts=border=\"0\" width=\"80%\"\@\@\n
\$\$/categorysection\@\@\n"; $template .= "\$\$protocolsection\@\@

Protocols

\n
\n\$\$protocollist cols=2 order=down atts=border=\"0\" width=\"80%\"\@\@\n
\$\$/protocolsection\@\@\n"; $template .= "\$\$functionsection\@\@

Functions

\n
\n\$\$functionlist cols=2 order=down atts=border=\"0\" width=\"80%\"\@\@\n
\$\$/functionsection\@\@\n"; $template .= "\$\$typesection\@\@

Data Types

\n
\n\$\$typelist cols=2 order=down atts=border=\"0\" width=\"80%\"\@\@\n
\$\$/typesection\@\@\n"; $template .= "\$\$datasection\@\@

Globals and Constants

\n
\n\$\$datalist cols=2 order=down atts=border=\"0\" width=\"80%\"\@\@\n
\$\$/datasection\@\@\n"; $template .= "\$\$propsection\@\@

Globals and Constants

\n
\n\$\$proplist cols=2 order=down atts=border=\"0\" width=\"80%\"\@\@\n
\$\$/propsection\@\@\n"; $template .= "\$\$copyright\@\@\n"; $template .= "\n\n"; $gather_globals_and_constants = 1; $gather_types = 1; $gather_functions = 1; return $template; } sub gethierlinkstring { my $group = shift; my $linkletter = shift; my $letter = shift; my $typename = shift; my $optional_last = ""; if (@_) { $optional_last = shift; $optional_last = "-$optional_last"; } elsif ($letter =~ /../) { $optional_last = $letter; $optional_last =~ s/(.)./$1Z/s; $optional_last = "-$optional_last"; } my $groupns = $group; $groupns =~ s/\s/_/sg; my $grouptype = $groupns."_".$typename; return "$letter$optional_last"; } sub genTable { my $inputstring = shift; my $settings = shift; my $groupname = shift; my $typename = shift; my $isman = 0; if (@_) { $isman = shift; } my $ncols = 0; my $order = "down"; my $attributes = "border=\"0\" width=\"100%\""; my $tdclass = ""; my $trclass = ""; my $localDebug = 0; my $addempty = 0; my $notable = 0; print "genTable(IS: [omitted], SET: $settings, GN: $groupname, TN: $typename, IM: $isman)\n" if ($localDebug); my $mansectiontext = ""; if ($isman) { my $mansectionname = $groupname; $mansectionname =~ s/^\s*Section\s+//s; my $filename="sectiondesc/man$mansectionname".".html"; if (open(SECTIONTEXT, "<$filename")) { my $lastrs = $/; $/ = undef; $mansectiontext = ; $/ = $lastrs; close(SECTIONTEXT); } else { warn "No file for man section $mansectionname\n"; } } if (!defined($inputstring)) { return ""; } my @lines = split(/\n/, $inputstring); my $nlines = scalar(@lines); my $addHierarchicalLinks = 0; my $hierstring = ""; if ($HeaderDoc::groupHierLimit && ($nlines > $HeaderDoc::groupHierLimit)) { $addHierarchicalLinks = 1; my $splitparts = 0; my $attempts = 0; my $subgroupLimit = $HeaderDoc::groupHierSubgroupLimit; my $minsplit = 5; while ($splitparts < $minsplit && $attempts < 5) { my $linkletter = ""; my $prevletter = ""; my $prevtwoletter = ""; $splitparts = 0; # Count the number of entries and reduce the limit as needed to ensure no singleton lists. $hierstring = "
\n"; print "GROUPNAME: $groupname\n" if ($localDebug); my $groupns = $groupname; $groupns =~ s/\s/_/sg; my $grouptype = $groupns."_".$typename; print "GROUPTYPE: \"$grouptype\"\n" if ($localDebug); my %twoletterlinkcounts = %{$group_letters_linked{$grouptype}}; print "GLLCHECK: ".scalar(keys %{$group_letters_linked{$grouptype}})."\n" if ($localDebug); my %oneletterlinkcounts = (); foreach my $twoletter (sort keys %twoletterlinkcounts) { # print "TL: $twoletter\n"; my $firstletter = $twoletter; $firstletter =~ s/^(.).*$/$1/s; if (!$oneletterlinkcounts{$firstletter}) { # print "FIRST $firstletter; linkletter -> $twoletter\n"; $oneletterlinkcounts{$firstletter} = $twoletterlinkcounts{$twoletter}; if ($prevletter ne "") { $hierstring .= gethierlinkstring($groupname, $linkletter, $prevletter, $typename)." | \n"; } $prevletter = $firstletter; $linkletter = $twoletter; $splitparts++; } elsif ($oneletterlinkcounts{$firstletter} + $twoletterlinkcounts{$twoletter} > $subgroupLimit) { # print "LIMIT $firstletter; linkletter -> $twoletter\n"; $hierstring .= gethierlinkstring($groupname, $linkletter, $prevletter, $typename, $prevtwoletter)." | \n"; $prevletter = $twoletter; $linkletter = $twoletter; $splitparts++; } $prevtwoletter = $twoletter; } if ($prevletter ne "") { $hierstring .= gethierlinkstring($groupname, $linkletter, $prevletter, $typename); } $hierstring .= "
\n"; # Reduce the subgroup limit and increase the attempt count so that if # we execute this code again, we will probably get more subgroups. # Use the attempts count to ensure that this loop isn't infinite if # all entries have the same first letter. if ($splitparts < $minsplit) { print "Minimum split count $minsplit not reached. Split count was $splitparts. Reducing split count.\n" if ($localDebug); $subgroupLimit = $subgroupLimit / $minsplit; } $attempts++; } print "SPLITPARTS: $splitparts\n" if ($localDebug); if ($splitparts <= 1) { print "Could not split list at all. Dropping singleton.\n" if ($localDebug); $hierstring = ""; # eliminate singleton lists. } # } else { # print "Not over limit: $groupname\n"; } # print "HIERSTRING: $hierstring\n"; my $ngroups = scalar(keys(%groups)); my $groupnamestring = ""; if ($groupname =~ /\S/) { my $groupnospc = $groupname; $groupnospc =~ s/\s/_/sg; $groupnamestring = "

$groupname

\n"; } if ($groupname eq "hd_master_letters_linked") { $groupnamestring = ""; } my $groupheadstring = "
\n"; my $grouptailstring = "
\n"; if (!$ngroups) { $groupheadstring = ""; $grouptailstring = ""; } $settings =~ s/^\s*(\w+list)\s*//; my $name = $1; if ($settings =~ s/^nogroups\s+//) { $ngroups = 0; } if ($settings =~ s/^cols=(\d+)\s+//) { $ncols = $1; } if ($settings =~ s/^order=(\w+)\s+//) { $order = $1; if (!$ncols) { $ncols = 1; } } if ($settings =~ s/^trclass=(\w+)\s+//) { $trclass = " class=\"$1\""; if (!$ncols) { $ncols = 1; } } if ($settings =~ s/^tdclass=(\w+)\s+//) { $tdclass = " class=\"$1\""; if (!$ncols) { $ncols = 1; } } if ($settings =~ s/^notable//) { $notable = 1; $ncols = 1; } if ($settings =~ s/^addempty=(\d+)//) { $addempty = $1; } if ($settings =~ s/^atts=//) { $attributes = $settings; $settings = ""; if (!$ncols) { $ncols = 1; } } if ($ncols) { if (!$nlines) { return ""; } my @columns = (); my $loopindex = $ncols; while ($loopindex--) { my @column = (); push(@columns, \@column); } my $curcolumn = 0; my $curline = 0; my $lines_per_column = int(($nlines + $ncols - 1) / $ncols); # ceil(nlines/ncols) my $blanks = ($lines_per_column * $ncols) - $nlines; $nlines += $blanks; while ($blanks) { push(@lines, ""); $blanks--; } warn "NLINES: $nlines\n" if ($localDebug); warn "Lines per column: $lines_per_column\n" if ($localDebug); foreach my $line (@lines) { warn "columns[$curcolumn] : adding line\n" if ($localDebug); my $columnref = $columns[$curcolumn]; push(@{$columnref}, $line); $curline++; if ($order eq "across") { $curcolumn = ($curcolumn + 1) % $ncols; } elsif ($curline >= $lines_per_column) { $curline = 0; $curcolumn++; } } if ($localDebug) { $loopindex = 0; while ($loopindex < $ncols) { warn "Column ".$loopindex.":\n"; foreach my $line (@{$columns[$loopindex]}) { warn "$line\n"; } $loopindex++; } } # warn("TABLE $attributes\n"); my $outstring = ""; if (!$notable) { $outstring .= ""; } $curline = 0; $curcolumn = 0; my $currow = 0; my $first = 1; while ($curline < $nlines) { if (!$curcolumn) { if ($first) { $first = 0; if (!$notable) { $outstring .= ""; } } else { if (!$notable) { $outstring .= "\n"; } $currow++; } } else { if ($addempty) { if (!$notable) { $outstring .= "\n"; } } } my $line = ${$columns[$curcolumn]}[$currow]; my $val = floor(100/$ncols); if ($notable) { $outstring .= "$line
\n"; } else { $outstring .= "$line\n"; } $curline++; $curcolumn = ($curcolumn + 1) % $ncols; } if (!$notable) { $outstring .= "
 
\n"; } return $groupnamestring.$mansectiontext.$hierstring.$groupheadstring.$outstring.$grouptailstring; } else { return $groupnamestring.$mansectiontext.$hierstring.$groupheadstring.$inputstring.$grouptailstring; } } sub pathparts { my $string = shift; my $count = 0; while ($string =~ s/\///) { $count++; } # print "PATHPARTS FOR $string: $count\n"; return $count; } sub rightframework { my $filename = shift; my $count = pathparts($filename); if ($frameworknestlevel == -1) { $frameworknestlevel = $count; return 1; } if ($frameworknestlevel < $count) { return 0; } return 1; } sub docListFromString { my $string = shift; my @parts = split(///s; my $string = "$name\n"; push(@list, $string); } } return @list; } sub relatedDocs { my $inputstring = shift; my $field = shift; my $retstring = ""; my $tmpstring = ""; if (length($inputstring)) { my @lines = docListFromString($inputstring); foreach my $line (@lines) { # print "LINE IS \"$line\"\n"; if (length($line)) { $tmpstring .= $line . "\n"; } } $tmpstring =~ s/\n$//s; $retstring .= genTable($tmpstring, $field, "", ""); } return $retstring; } sub groupList { my $string = ""; my $first = 1; foreach my $group (sort keys (%groups)) { if ($group !~ /\S/) { next; } if ($first) { $first = 0; } else { $string .= "  |  \n"; } my $groupnospc = $group; $groupnospc =~ s/\s/_/sg; my $groupnobr = $group; $groupnobr =~ s/\s/ /sg; $string .= "$groupnobr"; } # $string .= "
\n"; return $string; } sub printll { my $arrayref = shift; my $group = shift; my %arr = %{$arrayref}; print "FOR GROUP \"$group\"\n"; foreach my $key (sort keys %arr) { print "$key\n"; } print "\n"; } # sub writeAPIOwner # { # my $apioRef = shift; # my $file = shift; # # my $name = $apioRef->name(); # my $type = $apioRef->type(); # my $path = $apioRef->path(); # my $uid = $apioRef->uid(); # # print $file "\n"; # print $file " $name\n"; # print $file " $path\n"; # print $file " $uid\n"; # } sub generateDocSetFile { my $outputDir = shift; my $masterTOCFile = $outputDir.$pathSeparator.$masterTOCFileName; # my @allFramesetRefs; # my @headerFramesetRefs; # my @dataFramesetRefs; # my @macroFramesetRefs; # my @typeFramesetRefs; # my @comintFramesetRefs; # my @classFramesetRefs; # my @manpageFramesetRefs; # my @categoryFramesetRefs; # my @protocolFramesetRefs; # my @functionRefs; # foreach my $header (@headerFramesetRefs) { # writeAPIOwner($header, OUTFILE); # } open(OUTFILE, ">$inputDir/Nodes.xml") || die("Could not write Nodes.xml file.\n"); print OUTFILE "\n"; print OUTFILE "\n"; print OUTFILE " \n"; print OUTFILE " \n"; print OUTFILE " $framework\n"; print OUTFILE " $masterTOCFileName\n"; print OUTFILE " \n"; print OUTFILE " \n"; print OUTFILE "\n"; close(OUTFILE); open(OUTFILE, ">$inputDir/Tokens.xml") || die("Could not write Tokens.xml file.\n"); print OUTFILE "\n"; print OUTFILE "\n"; foreach my $header (@fileRefSets) { my $path = $header->path(); my $relPath = &findRelativePath($masterTOCFile, $path); my $arrayRef = $header->group(); my @refs = @{$arrayRef}; print OUTFILE " \n"; foreach my $ref (@refs) { my $uid = $ref->uid(); print OUTFILE " \n"; print OUTFILE " $uid\n"; # TODO: Availability print OUTFILE " \n"; } print OUTFILE " \n"; } print OUTFILE "\n"; close(OUTFILE); }