my $VERSION = 2.1;
my $isMacOS;
my $pathSeparator;
my $specifiedOutputDir;
my $export;
my $debugging;
my $testingExport = 0;
my $printVersion;
my $quietLevel;
my $xml_output;
my $write_control_file;
my $scriptDir;
my $lookupTableDirName;
my $lookupTableDir;
my $dbLookupTables;
my $functionFilename;
my $typesFilename;
my $enumsFilename;
my $masterTOCName;
my @inputFiles;
my @ignorePrefixes = ();
my @perHeaderIgnorePrefixes = ();
my $reprocess_input = 0;
my $functionGroup = "";
my @headerObjects; my @categoryObjects; my %objCClassNameToObject;
$| = 1;
my $modulesPath;
BEGIN {
use FindBin qw ($Bin);
use Cwd;
use Getopt::Std;
use File::Find;
my %options = ();
$lookupTableDirName = "LookupTables";
$functionFilename = "functions.tab";;
$typesFilename = "types.tab";
$enumsFilename = "enumConstants.tab";
$scriptDir = cwd();
if ($^O =~ /MacOS/i) {
$pathSeparator = ":";
$isMacOS = 1;
($modulesPath = $FindBin::Bin) =~ s/([^:]*):$/$1/;
} else {
$pathSeparator = "/";
$isMacOS = 0;
}
$modulesPath = "$FindBin::Bin"."$pathSeparator"."Modules";
foreach (qw(Mac::Files)) {
$MOD_AVAIL{$_} = eval "use $_; 1";
}
&getopts("HXhdvxquo:", \%options);
if ($options{v}) {
print "Getting version information for all modules. Please wait...\n";
$printVersion = 1;
return;
}
if ($options{h}) {
$write_control_file = "1";
} else {
$write_control_file = "0";
}
if ($options{u}) {
$HeaderDoc::sort_entries = 0;
} else {
$HeaderDoc::sort_entries = 1;
}
if ($options{H}) {
$HeaderDoc::insert_header = 1;
} else {
$HeaderDoc::insert_header = 0;
}
if ($options{q}) {
$quietLevel = "1";
} else {
$quietLevel = "0";
}
if ($options{d}) {
print "\tDebugging on...\n\n";
$debugging = 1;
}
if ($options{o}) {
$specifiedOutputDir = $options{o};
if (! -e $specifiedOutputDir) {
unless (mkdir ("$specifiedOutputDir", 0777)) {
die "Error: $specifiedOutputDir does not exist. Exiting. \n$!\n";
}
} elsif (! -d $specifiedOutputDir) {
die "Error: $specifiedOutputDir is not a directory. Exiting.\n$!\n";
} elsif (! -w $specifiedOutputDir) {
die "Error: Output directory $specifiedOutputDir is not writable. Exiting.\n$!\n";
}
if ($quietLevel eq "0") {
print "\nDocumentation will be written to $specifiedOutputDir\n";
}
}
$lookupTableDir = "$scriptDir$pathSeparator$lookupTableDirName";
if (($options{x}) || ($testingExport)) {
if ((-e "$lookupTableDir$pathSeparator$functionFilename") && (-e "$lookupTableDir$pathSeparator$typesFilename")) {
print "\nWill write database files to an Export directory within each top-level HTML directory.\n\n";
$export = 1;
} else {
print "\nLookup table files not available. Cannot export data.\n";
$export = 0;
$testingExport = 0;
}
}
if ($quietLevel eq "0") {
if ($options{X}) {
print "XML output mode.\n";
$xml_output = 1;
} else {
print "HTML output mode.\n";
$xml_output = 0;
}
}
if (($ my $inputDir = $ARGV[0];
if ($inputDir =~ /$pathSeparator$/) {
$inputDir =~ s|(.*)$pathSeparator$|$1|; }
if ($^O =~ /MacOS/i) {
find(\&getHeaders, $inputDir);
} else {
&find({wanted => \&getHeaders, follow => 1}, $inputDir);
}
} else {
print "Will process one or more individual files.\n" if ($debugging);
foreach my $singleFile (@ARGV) {
if (-f $singleFile) {
push(@inputFiles, $singleFile);
}
}
}
unless (@inputFiles) {
print "No valid input files specified. \n\n";
if ($isMacOS) {
die "\tTo use HeaderDoc, drop a header file or folder of header files on this application.\n\n";
} else {
die "\tUsage: headerdoc2html [-dq] [-o <output directory>] <input file(s) or directory>.\n\n";
}
}
sub getHeaders {
my $filePath = $File::Find::name;
my $fileName = $_;
if ($fileName =~ /\.h$/) {
push(@inputFiles, $filePath);
}
}
}
use strict;
use File::Copy;
use lib $modulesPath;
use HeaderDoc::DBLookup;
use HeaderDoc::Utilities qw(findRelativePath safeName getAPINameAndDisc printArray linesFromFile
printHash updateHashFromConfigFiles getHashFromConfigFile);
use HeaderDoc::Header;
use HeaderDoc::CClass;
use HeaderDoc::CPPClass;
use HeaderDoc::ObjCClass;
use HeaderDoc::ObjCProtocol;
use HeaderDoc::ObjCCategory;
use HeaderDoc::Function;
use HeaderDoc::Method;
use HeaderDoc::Typedef;
use HeaderDoc::Struct;
use HeaderDoc::Constant;
use HeaderDoc::Var;
use HeaderDoc::PDefine;
use HeaderDoc::Enum;
use HeaderDoc::MinorAPIElement;
my $localConfigFileName = "headerDoc2HTML.config";
my $preferencesConfigFileName = "com.apple.headerDoc2HTML.config";
my $homeDir;
my $usersPreferencesPath;
if ($^O =~ /MacOS/i) {
eval
{
require "FindFolder.pl";
$homeDir = MacPerl::FindFolder("D"); $usersPreferencesPath = MacPerl::FindFolder("P"); };
if ($@) {
import Mac::Files;
$homeDir = Mac::Files::FindFolder(kOnSystemDisk(), kDesktopFolderType());
$usersPreferencesPath = Mac::Files::FindFolder(kOnSystemDisk(), kPreferencesFolderType());
}
} else {
$homeDir = (getpwuid($<))[7];
$usersPreferencesPath = $homeDir.$pathSeparator."Library".$pathSeparator."Preferences";
}
my @configFiles = ($usersPreferencesPath.$pathSeparator.$preferencesConfigFileName, $Bin.$pathSeparator.$localConfigFileName);
my %config = (
copyrightOwner => "",
defaultFrameName => "index.html",
compositePageName => "CompositePage.html",
masterTOCName => "MasterTOC.html",
apiUIDPrefix => "apple_ref",
ignorePrefixes => "",
htmlHeader => ""
);
%config = &updateHashFromConfigFiles(\%config,\@configFiles);
if (defined $config{"ignorePrefixes"}) {
my $localDebug = 0;
my @prefixlist = split(/\|/, $config{"ignorePrefixes"});
foreach my $prefix (@prefixlist) {
print "ignoring $prefix\n" if ($localDebug);
push(@ignorePrefixes, $prefix);
}
}
if (defined $config{"copyrightOwner"}) {
HeaderDoc::APIOwner->copyrightOwner($config{"copyrightOwner"});
}
if (defined $config{"defaultFrameName"}) {
HeaderDoc::APIOwner->defaultFrameName($config{"defaultFrameName"});
}
if (defined $config{"compositePageName"}) {
HeaderDoc::APIOwner->compositePageName($config{"compositePageName"});
}
if (defined $config{"apiUIDPrefix"}) {
HeaderDoc::APIOwner->apiUIDPrefix($config{"apiUIDPrefix"});
}
if (defined $config{"htmlHeader"}) {
HeaderDoc::APIOwner->htmlHeader($config{"htmlHeader"});
}
if ($printVersion) {
&printVersionInfo();
exit;
}
if ($export || $testingExport) {
HeaderDoc::DBLookup->loadUsingFolderAndFiles($lookupTableDir, $functionFilename, $typesFilename, $enumsFilename);
}
my $inHeader = 0;
my $inCPPHeader = 0;
my $inClass = 0; my $inFunction = 0;
my $inFunctionGroup = 0;
my $inTypedef = 0;
my $inStruct = 0;
my $inUnion = 0;
my $inConstant = 0;
my $inVar = 0;
my $inPDefine = 0;
my $inEnum = 0;
my $inMethod = 0;
my $headerObject; my $rootFileName;
foreach my $inputFile (@inputFiles) {
my $constantObj;
my $enumObj;
my $funcObj;
my $methObj;
my $pDefineObj;
my $structObj;
my $typedefObj;
my $varObj;
my $cppAccessControlState = "protected:"; my $objcAccessControlState = "private:";
my @path = split (/$pathSeparator/, $inputFile);
my $filename = pop (@path);
if ($quietLevel eq "0") {
print "\nProcessing $filename\n";
}
@perHeaderIgnorePrefixes = ();
$reprocess_input = 0;
my $headerDir = join("$pathSeparator", @path);
($rootFileName = $filename) =~ s/\.(h|i)$//;
my $rootOutputDir;
if (length ($specifiedOutputDir)) {
$rootOutputDir ="$specifiedOutputDir$pathSeparator$rootFileName";
} elsif (@path) {
$rootOutputDir ="$headerDir$pathSeparator$rootFileName";
} else {
$rootOutputDir = $rootFileName;
}
my @rawInputLines = &linesFromFile($inputFile);
my @cookedInputLines;
my $localDebug = 0;
foreach my $line (@rawInputLines) {
foreach my $prefix (@ignorePrefixes) {
if ($line =~ s/^\s*$prefix\s*//g) {
print "ignored $prefix\n" if ($localDebug);
}
}
push(@cookedInputLines, $line);
}
@rawInputLines = @cookedInputLines;
REDO:
print "REDO" if ($debugging);
my @headerDocCommentLines = grep(/^\s*\/\*\!/, @rawInputLines);
if (!@headerDocCommentLines) {
if ($quietLevel eq "0") {
print " Skipping. No HeaderDoc comments found.\n";
}
next;
}
$headerObject = HeaderDoc::Header->new();
$HeaderDoc::headerObject = $headerObject;
if ($quietLevel eq "0") {
if ($xml_output) {
$headerObject->outputformat("hdxml");
} else {
$headerObject->outputformat("html");
}
}
$headerObject->outputDir($rootOutputDir);
$headerObject->name($filename);
$headerObject->filename($filename);
my $fullpath=cwd()."/$inputFile";
$headerObject->fullpath($fullpath);
my @lineArrays = &getLineArrays(\@rawInputLines);
my $localDebug = 0;
foreach my $arrayRef (@lineArrays) {
my @inputLines = @$arrayRef;
my $apiOwner = $headerObject; print "inHeader\n" if ($localDebug);
my $inputCounter = 0;
my $classType = "unknown";
while ($inputCounter <= $ my $line = "";
print "Input line number: $inputCounter\n" if ($localDebug);
if ($inputLines[$inputCounter] =~ /^\s*(public|private|protected)/) {
$cppAccessControlState = $&;
if ($inputLines[$inputCounter] =~ /^\s*(public|private|protected)\s*:/) {
$cppAccessControlState =~ s/^\s+//;
$cppAccessControlState =~ s/\s*:\s*$/$1/s;
$cppAccessControlState = "$cppAccessControlState:";
}
}
if ($inputLines[$inputCounter] =~ /^\s*(\@public|\@private|\@protected)/) {
$objcAccessControlState = $&;
if ($inputLines[$inputCounter] =~ /^\s*(\@public|\@private|\@protected)\s+/) {
$objcAccessControlState =~ s/^\s+//;
$objcAccessControlState =~ s/\s*:\s*$/$1/s;
$objcAccessControlState = "$objcAccessControlState:";
}
}
if ($inputLines[$inputCounter] =~ /^\s*\/\*\!/) { if ($inputLines[$inputCounter] =~ /\s*\*\//) { # closing comment marker on same line
$line .= $inputLines[$inputCounter++];
print "Input line number: $inputCounter\n" if ($localDebug);
} else { my $in_textblock = 0;
do {
my $templine = $inputLines[$inputCounter];
while ($templine =~ s/\@textblock//) { $in_textblock++; }
while ($templine =~ s/\@\/textblock//) { $in_textblock--; }
if (!$in_textblock) {
$inputLines[$inputCounter] =~ s/^[\t ]*[*]?[\t ]+(.*)$/$1/; }
my $newline = $inputLines[$inputCounter++];
$newline =~ s/^ \*//;
$line .= $newline;
print "Input line number: $inputCounter\n" if ($localDebug);
} while (($inputLines[$inputCounter] !~ /\*\//) && ($inputCounter <= $#inputLines));
my $newline = $inputLines[$inputCounter++];
if ($newline !~ /^ \*\//) {
$newline =~ s/^ \*//;
}
$line .= $newline; print "Input line number: $inputCounter\n" if ($localDebug);
}
$line =~ s/^\s+//; # trim leading whitespace
$line =~ s/^(.*)\*\/\s*$/$1/s;
SWITCH: { ($line =~ /^\/\*!\s+\@header\s*/i) && do {$inHeader = 1; last SWITCH;};
($line =~ /^\/\*!\s+\@template\s*/i) && do {$inClass = 1;last SWITCH;};
($line =~ /^\/\*!\s+\@class\s*/i) && do {$inClass = 1;last SWITCH;};
($line =~ /^\/\*!\s+\@protocol\s*/i) && do {$inClass = 1;last SWITCH;};
($line =~ /^\/\*!\s+\@category\s*/i) && do {$inClass = 1;last SWITCH;};
($line =~ /^\/\*!\s+\@language\s+.*c\+\+\s*/i) && do {$inCPPHeader = 1; last SWITCH;};
($line =~ /^\/\*!\s+\@functiongroup\s*/i) && do {$inFunctionGroup = 1;last SWITCH;};
($line =~ /^\/\*!\s+\@function\s*/i) && do {$inFunction = 1;last SWITCH;};
($line =~ /^\/\*!\s+\@method\s*/i) && do {
if ($classType eq "occ" ||
$classType eq "intf" ||
$classType eq "occCat") {
$inMethod = 1;last SWITCH;
} else {
$inFunction = 1;last SWITCH;
}
};
($line =~ /^\/\*!\s+\@typedef\s*/i) && do {$inTypedef = 1;last SWITCH;};
($line =~ /^\/\*!\s+\@union\s*/i) && do {$inUnion = 1;$inStruct = 1;last SWITCH;};
($line =~ /^\/\*!\s+\@struct\s*/i) && do {$inStruct = 1;last SWITCH;};
($line =~ /^\/\*!\s+\@const(ant)?\s*/i) && do {$inConstant = 1;last SWITCH;};
($line =~ /^\/\*!\s+\@var\s*/i) && do {$inVar = 1;last SWITCH;};
($line =~ /^\/\*!\s+\@define(d)?\s*/i) && do {$inPDefine = 1;last SWITCH;};
($line =~ /^\/\*!\s+\@enum\s*/i) && do {$inEnum = 1;last SWITCH;};
my $linenum = $inputCounter - 1;
print "$filename:$linenum:HeaderDoc comment is not of known type. Comment text is:\n";
print " $line\n";
}
my $linenum = $inputCounter - 1;
$line =~ s/\n\n/\n<br><br>\n/g; my @fields = split(/\@/, $line);
my @newfields = ();
my $lastappend = "";
my $in_textblock = 0;
foreach my $field (@fields) {
print "processing $field\n" if ($localDebug);
if ($in_textblock) {
if ($field =~ /^\/textblock/) {
print "out of textblock\n" if ($localDebug);
if ($in_textblock == 1) {
my $cleanfield = $field;
$cleanfield =~ s/^\/textblock//;
$lastappend .= $cleanfield;
push(@newfields, $lastappend);
print "pushed \"$lastappend\"\n" if ($localDebug);
$lastappend = "";
}
$in_textblock = 0;
} else {
$field =~ s/\</\<\;/g;
$field =~ s/\>/\>\;/g;
$lastappend .= "\@$field";
print "new field is \"$lastappend\"\n" if ($localDebug);
}
} else {
$field =~ s/^\/link\s*/<\/hd_link>/;
if ($field =~ s/^link\s+//) {
my $target = "";
my $lastfield;
if ($lastappend eq "") {
$lastfield = pop(@newfields);
} else {
$lastfield = "";
}
$lastappend .= $lastfield;
if ($field =~ /^(\S*?)\s/) {
$target = $1;
} else {
$target = $field;
}
my $localDebug = 0;
print "target $target\n" if ($localDebug);
$field =~ s/^$target//g;
$field =~ s/\\$/\@/;
$lastappend .= "<hd_link $target>";
$lastappend .= "$field";
} elsif ($field =~ /^textblock\s/) {
if ($lastappend eq "") {
$in_textblock = 1;
print "in textblock\n" if ($localDebug);
$lastappend = pop(@newfields);
} else {
$in_textblock = 2;
print "in textblock (continuation)\n" if ($localDebug);
}
$field =~ s/^textblock\s+//;
$field =~ s/\</\<\;/g;
$field =~ s/\>/\>\;/g;
$lastappend .= "$field";
print "in textblock.\n" if ($localDebug);
} elsif ($field =~ s/\\$/\@/) {
$lastappend .= $field;
} elsif ($lastappend eq "") {
push(@newfields, $field);
} else {
$lastappend .= $field;
push(@newfields, $lastappend);
$lastappend = "";
}
}
}
if (!($lastappend eq "")) {
push(@newfields, $lastappend);
}
@fields = @newfields;
if ($inCPPHeader) {print "inCPPHeader\n" if ($debugging); &processCPPHeaderComment();};
if ($inClass) {
my $classdec = "";
my $pos=$inputCounter;
do {
$classdec .= $inputLines[$pos];
} while (($pos < $ $classType = &determineClassType($inputCounter, $apiOwner, \@inputLines);
print "inClass 1 - $classType \n" if ($debugging);
$apiOwner = &processClassComment($apiOwner, $rootOutputDir, \@fields, $classType);
my $superclass = &get_super($classType, $classdec);
if (length($superclass)) {
$apiOwner->attribute("Superclass", $superclass, 0);
}
print "inClass 2\n" if ($debugging);
};
if ($inHeader) {
print "inHeader\n" if ($debugging);
$apiOwner = &processHeaderComment($apiOwner, $rootOutputDir, \@fields);
if ($reprocess_input == 1) {
my @cookedInputLines;
my $localDebug = 0;
foreach my $line (@rawInputLines) {
foreach my $prefix (@perHeaderIgnorePrefixes) {
if ($line =~ s/^\s*$prefix\s*//g) {
print "ignored $prefix\n" if ($localDebug);
}
}
push(@cookedInputLines, $line);
}
@rawInputLines = @cookedInputLines;
$reprocess_input = 2;
goto REDO;
}
};
if ($inFunctionGroup) {
print "inFunctionGroup\n" if ($debugging);
my $name = $line;
$name =~ s/.*\/\*!\s+\@functiongroup\s*//i;
$name =~ s/\s*\*\/.*//;
$name =~ s/\n//smg;
$name =~ s/^\s+//smg;
$name =~ s/\s+$//smg;
$functionGroup = $name;
};
if ($inFunction) {
print "inFunction $line\n" if ($localDebug);
$funcObj = HeaderDoc::Function->new;
if ($xml_output) {
$funcObj->outputformat("hdxml");
} else {
$funcObj->outputformat("html");
}
\ $funcObj->group($functionGroup);
$funcObj->processFunctionComment(\@fields);
while ((($inputLines[$inputCounter] =~ /^%CPassThru/) || ($inputLines[$inputCounter] !~ /\w/)) && ($inputCounter <= $ $inputCounter++;
print "Input line number: $inputCounter\n" if ($localDebug);
};
if ($inputLines[$inputCounter] =~ /^ print "macro\n" if ($localDebug);
my $declaration = $inputLines[$inputCounter];
while (($declaration =~ /\\\n$/) && ($inputCounter <= $ $inputCounter++;
$declaration .= $inputLines[$inputCounter];
print "Input line number: $inputCounter\n" if ($localDebug);
}; $funcObj->setFunctionDeclaration($declaration);
} else { my $declaration = $inputLines[$inputCounter];
if ($declaration !~ /;[^;]*$/) { do {
$inputCounter++;
print "Input line number: $inputCounter\n" if ($localDebug);
$declaration .= $inputLines[$inputCounter];
} while (($declaration !~ /;[^;]*$/) && ($inputCounter <= $ }
$declaration =~ s/^\s+//g; # trim leading spaces.
$declaration =~ s/([^;]*;).*$/$1/s; $declaration =~ s/([^{]+){.*;$/$1;/s; $declaration =~ s/\s+;/;/; if ($declaration =~ /^virtual.*/) {
$funcObj->linkageState("virtual");
} elsif ($declaration =~ /^static.*/) {
$funcObj->linkageState("static");
} else {
$funcObj->linkageState("other");
}
$funcObj->setFunctionDeclaration($declaration);
}
if (length($funcObj->name())) {
if (ref($apiOwner) ne "HeaderDoc::Header") {
if ($classType eq "occ" ||
$classType eq "intf" ||
$classType eq "occCat") {
$funcObj->accessControl($objcAccessControlState);
} else {
$funcObj->accessControl($cppAccessControlState);
}
}
$apiOwner->addToFunctions($funcObj);
}
}
if ($inMethod) {
my $methodDebug = 0;
print "inMethod $line\n" if ($methodDebug);
$methObj = HeaderDoc::Method->new;
if ($xml_output) {
$methObj->outputformat("hdxml");
} else {
$methObj->outputformat("html");
}
$methObj->processMethodComment(\@fields);
while (($inputLines[$inputCounter] !~ /\w/) && ($inputCounter <= $ $inputCounter++;
print "Input line number: $inputCounter\n" if ($localDebug);
};
my $declaration = $inputLines[$inputCounter];
if ($declaration !~ /;[^;]*$/) { do {
$inputCounter++;
print "Input line number: $inputCounter\n" if ($localDebug);
$declaration .= $inputLines[$inputCounter];
} while (($declaration !~ /;[^;]*$/) && ($inputCounter <= $ }
$declaration =~ s/^\s+//g; # trim leading spaces.
$declaration =~ s/([^;]*;).*$/$1/s; $declaration =~ s/\s+;/;/;
print " --> setting method declaration: $declaration\n" if ($methodDebug);
$methObj->setMethodDeclaration($declaration, $classType);
if (length($methObj->name())) {
if (ref($apiOwner) ne "HeaderDoc::Header") {
if ($classType eq "occ" ||
$classType eq "intf" ||
$classType eq "occCat") {
$methObj->accessControl($objcAccessControlState);
} else {
$methObj->accessControl($cppAccessControlState);
}
}
$apiOwner->addToMethods($methObj);
$methObj->owner($apiOwner); print "added method $declaration\n" if ($localDebug);
}
}
if ($inTypedef) {
$typedefObj = HeaderDoc::Typedef->new;
if ($xml_output) {
$typedefObj->outputformat("hdxml");
} else {
$typedefObj->outputformat("html");
}
$typedefObj->processTypedefComment(\@fields);
my $typedefName = $typedefObj->name();
while (($inputLines[$inputCounter] !~ /\w/) && ($inputCounter <= $ $inputCounter++;
print "Input line number: $inputCounter\n" if ($localDebug);
};
my $declaration = $inputLines[$inputCounter];
if ($declaration !~ /typedef/) {
while (($inputLines[$inputCounter] !~ /typedef/) && ($inputCounter <= $ $declaration .= $inputLines[++$inputCounter];
print "Input line number: $inputCounter\n" if ($localDebug);
};
} else {
if ($declaration =~ /{/) { print "Entered case for $declaration, $typedefName\n" if ($localDebug);
my $bracecount=0;
my $test = $inputLines[$inputCounter];
$bracecount += ($test =~ tr/{//);
$test = $inputLines[$inputCounter];
$bracecount -= ($test =~ tr/}//);
print "Entered with count $bracecount\n" if ($localDebug);
while ((($inputLines[$inputCounter] !~ /}/)
|| ($bracecount > 0))
&& ($inputCounter <= $ $declaration .= $inputLines[++$inputCounter];
$test = $inputLines[$inputCounter];
$bracecount += ($test =~ tr/{//);
$test = $inputLines[$inputCounter];
$bracecount -= ($test =~ tr/}//);
print "count $bracecount\n" if ($localDebug);
print "Input line number: $inputCounter\n" if ($localDebug);
};
print "count $bracecount left with declaration $declaration\n" if ($localDebug);
} else {
while (($inputLines[$inputCounter] !~ /;/) && ($inputCounter <= $ $declaration .= $inputLines[++$inputCounter];
print "Input line number: $inputCounter\n" if ($localDebug);
}
}
}
if (length($declaration)) {
$typedefObj->setTypedefDeclaration($declaration);
} else {
print "$filename:$linenum:Couldn't find a declaration for typedef\n";
}
if (length($typedefObj->name())) {
if (ref($apiOwner) ne "HeaderDoc::Header") {
$typedefObj->accessControl($cppAccessControlState);
$apiOwner->addToVars($typedefObj);
} else { $apiOwner->addToTypedefs($typedefObj);
}
}
}
if ($inStruct) {
$structObj = HeaderDoc::Struct->new;
if ($inUnion) {
$structObj->isUnion(1);
} else {
$structObj->isUnion(0);
}
if ($xml_output) {
$structObj->outputformat("hdxml");
} else {
$structObj->outputformat("html");
}
$structObj->processStructComment(\@fields);
while (($inputLines[$inputCounter] !~ /\w/) && ($inputCounter <= $ my $declaration = $inputLines[$inputCounter];
while ($inputLines[$inputCounter] !~ /}/ && ($inputCounter <= $ if (length($declaration)) {
$structObj->setStructDeclaration($declaration);
} else {
warn "$filename:$linenum:Couldn't find a declaration for struct\n";
}
if (length($structObj->name())) {
if (ref($apiOwner) ne "HeaderDoc::Header") {
$structObj->accessControl($cppAccessControlState);
$apiOwner->addToVars($structObj);
} else { $apiOwner->addToStructs($structObj);
}
}
}
if ($inConstant) {
$constantObj = HeaderDoc::Constant->new;
if ($xml_output) {
$constantObj->outputformat("hdxml");
} else {
$constantObj->outputformat("html");
}
$constantObj->processConstantComment(\@fields);
while (($inputLines[$inputCounter] !~ /\w/) && ($inputCounter <= $ if ($inputLines[$inputCounter] =~ /^\s*(const|extern|CF_EXPORT)/) {
my $declaration = $inputLines[$inputCounter];
if ($declaration !~ /;\s*$/) {
$inputCounter++;
print "Input line number: $inputCounter\n" if ($localDebug);
while (($declaration !~ /\s*;\s*$/) && ($inputCounter <= $ }
$declaration =~ s/CF_EXPORT\s+//;
$constantObj->setConstantDeclaration($declaration);
}
if (length($constantObj->name())) {
if (ref($apiOwner) ne "HeaderDoc::Header") {
$constantObj->accessControl($cppAccessControlState);
$apiOwner->addToVars($constantObj);
} else { $apiOwner->addToConstants($constantObj);
}
}
}
if ($inVar) {
$varObj = HeaderDoc::Var->new;
if ($xml_output) {
$varObj->outputformat("hdxml");
} else {
$varObj->outputformat("html");
}
$varObj->processVarComment(\@fields);
while (($inputLines[$inputCounter] !~ /\w/) && ($inputCounter <= $ my $declaration = &removeSlashSlashComment($inputLines[$inputCounter]);
if ($declaration !~ /;\s*$/) {
$inputCounter++;
print "Input line number: $inputCounter\n" if ($localDebug);
while (($declaration !~ /}\s*;\s*$/) && ($inputCounter <= $ }
$varObj->setVarDeclaration($declaration);
if (length($varObj->name())) {
if (ref($apiOwner) ne "HeaderDoc::Header") {
if ($classType eq "occ" ||
$classType eq "intf" ||
$classType eq "occCat") {
$varObj->accessControl($objcAccessControlState);
} else {
$varObj->accessControl($cppAccessControlState);
}
$apiOwner->addToVars($varObj);
} else { warn "$filename:$linenum:\@var tag found outside of a class declaration. \n";
$varObj->printObject();
$apiOwner->addToVars($varObj); }
}
}
if ($inPDefine) {
$pDefineObj = HeaderDoc::PDefine->new;
if ($xml_output) {
$pDefineObj->outputformat("hdxml");
} else {
$pDefineObj->outputformat("html");
}
$pDefineObj->processPDefineComment(\@fields);
while (($inputLines[$inputCounter] !~ /\w/) && ($inputCounter <= $ my $declaration;
if ($inputLines[$inputCounter] =~ /^\s* while (($inputLines[$inputCounter] =~ /^\s* $declaration .= $inputLines[$inputCounter];
if ($declaration =~ /\\\n$/) { while (($declaration =~ /\\\n$/) && ($inputCounter <= $ }
$inputCounter++;
print "Input line number: $inputCounter\n" if ($localDebug);
}
$inputCounter--;
} else {
warn "$filename:$linenum:Can't find declaration for \@define comment with name:\n";
my $name = $pDefineObj->name();
warn "$filename:$linenum:$name\n\n";
}
$pDefineObj->setPDefineDeclaration($declaration);
if (length($pDefineObj->name())) {
if (ref($apiOwner) ne "HeaderDoc::Header") {
$pDefineObj->accessControl($cppAccessControlState);
$apiOwner->addToVars($pDefineObj);
} else { $apiOwner->addToPDefines($pDefineObj);
}
}
}
if ($inEnum) {
$enumObj = HeaderDoc::Enum->new;
if ($xml_output) {
$enumObj->outputformat("hdxml");
} else {
$enumObj->outputformat("html");
}
$enumObj->processEnumComment(\@fields);
while (($inputLines[$inputCounter] !~ /\w/) && ($inputCounter <= $ my $declaration = $inputLines[$inputCounter];
while (($inputLines[$inputCounter] !~ /}/) && ($inputCounter <= $
if (length($declaration)) {
$enumObj->declarationInHTML($enumObj->getEnumDeclaration($declaration));
} else {
warn "$filename:$linenum:Couldn't find a declaration for enum near line: $inputCounter\n";
}
if (length($enumObj->name())) {
if (ref($apiOwner) ne "HeaderDoc::Header") {
$enumObj->accessControl($cppAccessControlState);
$apiOwner->addToVars($enumObj);
} else { $apiOwner->addToEnums($enumObj);
}
}
} }
$inHeader = $inFunction = $inFunctionGroup = $inTypedef = $inUnion = $inStruct = $inConstant = $inVar = $inPDefine = $inEnum = $inMethod = $inClass = 0;
$inputCounter++;
print "Input line number: $inputCounter\n" if ($localDebug);
}
if (ref($apiOwner) ne "HeaderDoc::Header") { my $name = $apiOwner->name();
my $refName = ref($apiOwner);
SWITCH: {
($classType eq "cpp" ) && do {
$headerObject->addToClasses($apiOwner);
last SWITCH; };
($classType eq "cppt" ) && do {
$headerObject->addToClasses($apiOwner);
last SWITCH; };
($classType eq "occ") && do {
$headerObject->addToClasses($apiOwner);
$objCClassNameToObject{$apiOwner->name()} = $apiOwner;
last SWITCH; };
($classType eq "intf") && do {
$headerObject->addToProtocols($apiOwner);
last SWITCH;
};
($classType eq "occCat") && do {
push (@categoryObjects, $apiOwner);
$headerObject->addToCategories($apiOwner);
last SWITCH;
};
($classType eq "C") && do {
$cppAccessControlState = "public:";
$headerObject->addToClasses($apiOwner);
last SWITCH;
};
my $linenum = $inputCounter - 1;
print "$filename:$linenum:Unknown class type '$classType' (known: cpp, objC, intf, occCat)\n";
}
}
} push (@headerObjects, $headerObject);
}
if (@categoryObjects && !$xml_output) {
foreach my $obj (@categoryObjects) {
my $nameOfAssociatedClass = $obj->className();
my $categoryName = $obj->categoryName();
my $localDebug = 0;
if (exists $objCClassNameToObject{$nameOfAssociatedClass}) {
my $associatedClass = $objCClassNameToObject{$nameOfAssociatedClass};
$associatedClass->addToMethods($obj->methods());
my $owner = $obj->headerObject();
print "Found category with name $categoryName and associated class $nameOfAssociatedClass\n" if ($localDebug);
print "Associated class exists\n" if ($localDebug);
print "Added methods to associated class\n" if ($localDebug);
if (ref($owner)) {
my $numCatsBefore = $owner->categories();
$owner->removeFromCategories($obj);
my $numCatsAfter = $owner->categories();
print "Number of categories before: $numCatsBefore after:$numCatsAfter\n" if ($localDebug);
} else {
my $filename = $HeaderDoc::headerObject->filename();
print "$filename:0:Couldn't find Header object that owns the category with name $categoryName.\n";
}
} else {
print "Found category with name $categoryName and associated class $nameOfAssociatedClass\n" if ($localDebug);
print "Associated class doesn't exist\n" if ($localDebug);
}
}
}
foreach my $obj (@headerObjects) {
if ($xml_output) {
$obj->writeHeaderElementsToXMLPage();
} else {
$obj->createFramesetFile();
$obj->createTOCFile();
$obj->writeHeaderElements();
$obj->writeHeaderElementsToCompositePage();
$obj->createContentFile();
$obj->writeExportsWithName($rootFileName) if (($export) || ($testingExport));
}
if ("$write_control_file" eq "1") {
print "Writing doc server control file... ";
$obj->createMetaFile();
print "done.\n";
}
}
if ($quietLevel eq "0") {
print "...done\n";
}
exit 0;
sub getLineArrays {
my $rawLineArrayRef = shift;
my @arrayOfLineArrays = ();
my @generalHeaderLines = ();
my $inputCounter = 0;
my $lastArrayIndex = @{$rawLineArrayRef};
my $line = "";
my $className = "";
while ($inputCounter <= $lastArrayIndex) {
$line = ${$rawLineArrayRef}[$inputCounter];
if (($line =~ /^\/\*\!/)) {
my $headerDocComment = "";
my $classType = "";
{
local $^W = 0; my $in_textblock = 0;
while (($line !~ /\*\//) && ($inputCounter <= $lastArrayIndex)) {
my $templine = $line;
while ($templine =~ s/\@textblock//) { $in_textblock++; }
while ($templine =~ s/\@\/textblock//) { $in_textblock--; }
if (!$in_textblock) {
$line =~ s/^[ \t]*//; # remove leading whitespace
}
$line =~ s/^[*]\s*$/\n/; $line =~ s/^[*]\s+(.*)/$1/; $headerDocComment .= $line;
$line = ${$rawLineArrayRef}[++$inputCounter];
}
$headerDocComment .= $line
}
if ($headerDocComment =~ /^\/\*!\s+\@class|\@protocol|\@category\s*/i) {
my @classLines;
($className = $headerDocComment) =~ s/.*\@class|\@protocol|\@category\s+(\w+)\s+.*/$1/s;
push (@classLines, $headerDocComment);
while (($line !~ /class\s|\@interface\s|\@protocol\s|typedef\s+struct\s/) && ($inputCounter <= $lastArrayIndex)) {
$line = ${$rawLineArrayRef}[$inputCounter];
push (@classLines, $line);
$inputCounter++;
}
my $initial_bracecount = ($line =~ tr/{//) - ($line =~ tr/}//);
SWITCH: {
($line =~ s/^\s*\@protocol\s+// ) &&
do {
$classType = "objCProtocol";
last SWITCH;
};
($line =~ s/^\s*typedef\s+struct\s+// ) &&
do {
$classType = "C";
last SWITCH;
};
($line =~ s/^\s*template\s+// ) &&
do {
$classType = "cppt";
last SWITCH;
};
($line =~ s/^\s*class\s+// ) &&
do {
$classType = "cpp";
last SWITCH;
};
($line =~ s/^\s*\@interface\s+// ) &&
do {
if ($line =~ /\(.*\)/) {
$classType = "objCCategory";
} else {
$classType = "objC";
}
last SWITCH;
};
print "Unknown class type (known: cpp, cppt, objCCategory, objCProtocol, C,)\nline=\"$line\"";
}
my $inClassBraces = $initial_bracecount;
my $leftBraces = 0;
my $rightBraces = 0;
do {
$line = ${$rawLineArrayRef}[$inputCounter];
push (@classLines, $line);
$inputCounter++;
$leftBraces = $line =~ tr/{//;
$rightBraces = $line =~ tr/}//;
$inClassBraces += $leftBraces;
$inClassBraces -= $rightBraces;
} while (($inputCounter <= $lastArrayIndex)
&& (!($leftBraces)));
if (($classType =~ s/cpp//) || ($classType =~ s/^C//) || ($classType =~ s/cppt//)) {
while ($inClassBraces && ($inputCounter <= $lastArrayIndex)) {
$line = ${$rawLineArrayRef}[$inputCounter];
push (@classLines, $line);
$leftBraces = $line =~ tr/{//;
$rightBraces = $line =~ tr/}//;
$inClassBraces += $leftBraces;
$inClassBraces -= $rightBraces;
$inputCounter++;
}
}
if (($classType =~ s/objC//) || ($classType =~ s/objCProtocol//) || ($classType =~ s/objCCategory//)) {
while (($line !~ /\@end/) && ($inputCounter <= $lastArrayIndex)) {
$line = ${$rawLineArrayRef}[$inputCounter];
push (@classLines, $line);
$inputCounter++;
}
}
push (@arrayOfLineArrays, \@classLines);
$inputCounter--;
} else {
push (@generalHeaderLines, $headerDocComment);
}
}
push (@generalHeaderLines, $line);
$inputCounter++;
}
push (@arrayOfLineArrays, \@generalHeaderLines);
return @arrayOfLineArrays;
}
sub processCPPHeaderComment {
return;
}
sub removeSlashSlashComment {
my $line = shift;
$line =~ s/\/\/.*$//;
return $line;
}
sub get_super {
my $classType = shift;
my $dec = shift;
my $super = "";
my $localDebug = 0;
$dec =~ s/\n/ /smg;
if ($classType =~ /^occ/) {
if ($dec !~ s/^\s*\@interface\s*//s) {
$dec =~ s/^\s*\@protocol\s*//s;
}
if (!($dec =~ s/.*?://s)) {
$super = "";
} else {
$dec =~ s/\(.*//sg;
$dec =~ s/\{.*//sg;
$super = $dec;
}
} elsif ($classType =~ /^cpp$/) {
$dec !~ s/^\s*\class\s*//s;
if (!($dec =~ s/.*?://s)) {
$super = "";
} else {
$dec =~ s/\(.*//sg;
$dec =~ s/\{.*//sg;
$dec =~ s/^\s*//sg;
$dec =~ s/^public//g;
$dec =~ s/^private//g;
$dec =~ s/^protected//g;
$dec =~ s/^virtual//g;
$super = $dec;
}
}
$super =~ s/^\s*//;
$super =~ s/\s.*//;
print "$super is super\n" if ($localDebug);
return $super;
}
sub determineClassType {
my $lineCounter = shift;
my $apiOwner = shift;
my $inputLinesRef = shift;
my @inputLines = @$inputLinesRef;
my $classType = "unknown";
my $tempLine = "";
do {
$tempLine = $inputLines[$lineCounter];
$lineCounter++;
} while (($tempLine !~ /class|\@interface|\@protocol|typedef\s+struct/) && ($lineCounter <= $
if ($tempLine =~ s/class\s//) {
$classType = "cpp";
}
if ($tempLine =~ s/typedef\s+struct\s//) {
$classType = "C"; }
if ($tempLine =~ s/\@interface\s//) {
if ($tempLine =~ /\(.*\)/) {
$classType = "occCat"; } else {
$classType = "occ";
}
}
if ($tempLine =~ s/\@protocol\s//) {
$classType = "intf";
}
return $classType;
}
sub processClassComment {
my $apiOwner = shift;
my $headerObj = $apiOwner;
my $rootOutputDir = shift;
my $fieldArrayRef = shift;
my @fields = @$fieldArrayRef;
my $classType = shift;
my $filename = $HeaderDoc::headerObject->filename();
SWITCH: {
($classType eq "cpp" ) && do { $apiOwner = HeaderDoc::CPPClass->new; $apiOwner->filename($filename); last SWITCH; };
($classType eq "cppt" ) && do { $apiOwner = HeaderDoc::CPPClass->new; $apiOwner->filename($filename); last SWITCH; };
($classType eq "occ") && do { $apiOwner = HeaderDoc::ObjCClass->new; $apiOwner->filename($filename); last SWITCH; };
($classType eq "occCat") && do { $apiOwner = HeaderDoc::ObjCCategory->new; $apiOwner->filename($filename); last SWITCH; };
($classType eq "intf") && do { $apiOwner = HeaderDoc::ObjCProtocol->new; $apiOwner->filename($filename); last SWITCH; };
($classType eq "C") && do { $apiOwner = HeaderDoc::CClass->new; $apiOwner->filename($filename); last SWITCH; };
print "Unknown type (known: classes (ObjC and C++), ObjC categories and protocols)\n";
}
$HeaderDoc::currentClass = $apiOwner;
if ($xml_output) {
$apiOwner->outputformat("hdxml");
} else {
$apiOwner->outputformat("html");
}
$apiOwner->headerObject($headerObj);
$apiOwner->outputDir($rootOutputDir);
foreach my $field (@fields) {
SWITCH: {
($field =~ /^\/\*\!/) && do {last SWITCH;}; ($field =~ s/^class\s+//) &&
do {
my ($name, $disc);
($name, $disc) = &getAPINameAndDisc($field);
my $classID = ref($apiOwner);
if (length($name)) {
$apiOwner->name($name);
} else {
my $filename = $HeaderDoc::headerObject->filename();
print "$filename:0:Did not find class name following \@class tag!\n";
}
if (length($disc)) {$apiOwner->discussion($disc);};
last SWITCH;
};
($field =~ s/^protocol\s+//) &&
do {
my ($name, $disc);
($name, $disc) = &getAPINameAndDisc($field);
if (length($name)) {
$apiOwner->name($name);
} else {
my $filename = $HeaderDoc::headerObject->filename();
warn "$filename:0:Did not find protocol name following \@protocol tag!\n";
}
if (length($disc)) {$apiOwner->discussion($disc);};
last SWITCH;
};
($field =~ s/^category\s+//) &&
do {
my ($name, $disc);
($name, $disc) = &getAPINameAndDisc($field);
if (length($name)) {
$apiOwner->name($name);
} else {
my $filename = $HeaderDoc::headerObject->filename();
warn "$filename:0:Did not find category name following \@protocol tag!\n";
}
if (length($disc)) {$apiOwner->discussion($disc);};
last SWITCH;
};
($field =~ s/^templatefield\s+//) && do {
$field =~ s/^\s+|\s+$//g;
$field =~ /(\w*)\s*(.*)/s;
my $fName = $1;
my $fDesc = $2;
my $fObj = HeaderDoc::MinorAPIElement->new();
$fObj->outputformat($apiOwner->outputformat);
$fObj->name($fName);
$fObj->discussion($fDesc);
$apiOwner->addToFields($fObj);
last SWITCH;
};
($field =~ s/^throws\s+//) && do {$apiOwner->throws($field); last SWITCH;};
($field =~ s/^exception\s+//) && do {$apiOwner->throws($field); last SWITCH;};
($field =~ s/^abstract\s+//) && do {$apiOwner->abstract($field); last SWITCH;};
($field =~ s/^discussion\s+//) && do {$apiOwner->discussion($field); last SWITCH;};
($field =~ s/^availability\s+//) && do {$apiOwner->availability($field); last SWITCH;};
($field =~ s/^updated\s+//) && do {$apiOwner->updated($field); last SWITCH;};
($field =~ s/^namespace\s+//) && do {$apiOwner->namespace($field); last SWITCH;};
($field =~ s/^instancesize\s+//) && do {$apiOwner->attribute("Instance Size", $field, 0); last SWITCH;};
($field =~ s/^performance\s+//) && do {$apiOwner->attribute("Performance", $field, 1); last SWITCH;};
($field =~ s/^nestedclass\s+//) && do {$apiOwner->attributelist("Nested Classes", $field); last SWITCH;};
($field =~ s/^coclass\s+//) && do {$apiOwner->attributelist("Co-Classes", $field); last SWITCH;};
($field =~ s/^helper(class|)\s+//) && do {$apiOwner->attributelist("Helper Classes", $field); last SWITCH;};
($field =~ s/^helps\s+//) && do {$apiOwner->attribute("Helps", $field, 0); last SWITCH;};
($field =~ s/^classdesign\s+//) && do {$apiOwner->attribute("Class Design", $field, 1); last SWITCH;};
($field =~ s/^dependency\s+//) && do {$apiOwner->attributelist("Dependencies", $field); last SWITCH;};
($field =~ s/^ownership\s+//) && do {$apiOwner->attribute("Ownership Model", $field, 1); last SWITCH;};
($field =~ s/^security\s+//) && do {$apiOwner->attribute("Security", $field, 1); last SWITCH;};
($field =~ s/^whysubclass\s+//) && do {$apiOwner->attribute("Reason to Subclass", $field, 1); last SWITCH;};
print "Unknown field in class comment: $field\n";
}
}
return $apiOwner;
}
sub processHeaderComment {
my $apiOwner = shift;
my $rootOutputDir = shift;
my $fieldArrayRef = shift;
my @fields = @$fieldArrayRef;
my $localDebug = 0;
foreach my $field (@fields) {
SWITCH: {
($field =~ /^\/\*\!/)&& do {last SWITCH;}; ($field =~ s/^header\s+//) &&
do {
my ($name, $disc);
($name, $disc) = &getAPINameAndDisc($field);
my $longname = $name; if (length($name)) {
print "Setting header name to $longname\n" if ($debugging);
$apiOwner->name($longname);
}
print "Discussion is:\n" if ($debugging);
print "$disc\n" if ($debugging);
if (length($disc)) {$apiOwner->discussion($disc);};
last SWITCH;
};
($field =~ s/^availability\s+//) && do {$apiOwner->availability($field); last SWITCH;};
($field =~ s/^updated\s+//) && do {$apiOwner->updated($field); last SWITCH;};
($field =~ s/^abstract\s+//) && do {$apiOwner->abstract($field); last SWITCH;};
($field =~ s/^discussion\s+//) && do {$apiOwner->discussion($field); last SWITCH;};
($field =~ s/^copyright\s+//) && do { $apiOwner->headerCopyrightOwner($field); last SWITCH;};
($field =~ s/^meta\s+//) && do {$apiOwner->HTMLmeta($field); last SWITCH;};
($field =~ s/^CFBundleIdentifier\s+//i) && do {$apiOwner->attribute("CFBundleIdentifier", $field, 0); last SWITCH;};
($field =~ s/^related\s+//i) && do {$apiOwner->attributelist("Related Headers", $field); last SWITCH;};
($field =~ s/^(compiler|)flag\s+//) && do {$apiOwner->attributelist("Compiler Flags", $field); last SWITCH;};
($field =~ s/^preprocinfo\s+//) && do {$apiOwner->attribute("Preprocessor Behavior", $field, 1); last SWITCH;};
($field =~ s/^whyinclude\s+//) && do {$apiOwner->attribute("Reason to Include", $field, 1); last SWITCH;};
($field =~ s/^ignore\s+//) && do { $field =~ s/\n//smg; push(@perHeaderIgnorePrefixes, $field); if (!($reprocess_input)) {$reprocess_input = 1;} print "ignoring $field" if ($localDebug); last SWITCH;};
print "Unknown field in header comment: $field\n";
}
}
return $apiOwner;
}
sub printVersionInfo {
my $av = HeaderDoc::APIOwner->VERSION();
my $hev = HeaderDoc::HeaderElement->VERSION();
my $hv = HeaderDoc::Header->VERSION();
my $cppv = HeaderDoc::CPPClass->VERSION();
my $objcv = HeaderDoc::ObjCClass->VERSION();
my $objcprotocolv = HeaderDoc::ObjCProtocol->VERSION();
my $fv = HeaderDoc::Function->VERSION();
my $mv = HeaderDoc::Method->VERSION();
my $tv = HeaderDoc::Typedef->VERSION();
my $sv = HeaderDoc::Struct->VERSION();
my $cv = HeaderDoc::Constant->VERSION();
my $vv = HeaderDoc::Var->VERSION();
my $ev = HeaderDoc::Enum->VERSION();
my $uv = HeaderDoc::Utilities->VERSION();
my $me = HeaderDoc::MinorAPIElement->VERSION();
print "----------------------------------------------------\n";
print "\tHeaderDoc version $VERSION.\n";
print "\tModules:\n";
print "\t\tAPIOwner - $av\n";
print "\t\tHeaderElement - $hev\n";
print "\t\tHeader - $hv\n";
print "\t\tCPPClass - $cppv\n";
print "\t\tObjClass - $objcv\n";
print "\t\tObjCProtocol - $objcprotocolv\n";
print "\t\tFunction - $fv\n";
print "\t\tMethod - $mv\n";
print "\t\tTypedef - $tv\n";
print "\t\tStruct - $sv\n";
print "\t\tConstant - $cv\n";
print "\t\tEnum - $ev\n";
print "\t\tVar - $vv\n";
print "\t\tMinorAPIElement - $me\n";
print "\t\tUtilities - $uv\n";
print "----------------------------------------------------\n";
}