my $HeaderDoc_Version = "8.9";
my $VERSION = '$Revision: 1392429329 $';
$HeaderDoc::defaultHeaderComment = "Use the links in the table of contents to the left to access the documentation.<br>\n";
$HeaderDoc::parseIfElse = 0;
$HeaderDoc::nameFromAPIRefReturnsOnlyName = 0;
$HeaderDoc::testsuite_version="0";
my $isMacOS;
my $pathSeparator;
my $specifiedOutputDir;
my $debugging = 0;
my $printVersion;
my $quietLevel;
my $xml_output;
my $man_output;
my $function_list_output;
my $doxytag_output;
my $headerdoc_strip;
my $use_stdout;
my $regenerate_headers;
my $lang = "C";
my @inputFiles;
my @doxyTagFiles;
$HeaderDoc::currentClass = undef;
$HeaderDoc::perlClassChange = undef;
$HeaderDoc::enable_reverse_match = 0;
$HeaderDoc::reverse_match = 0;
$HeaderDoc::interpret_case = 0;
my $reprocess_input = 0;
my $functionGroup = "";
$HeaderDoc::globalGroup = "";
$HeaderDoc::hidetokens = 0;
$HeaderDoc::exitstatus = 0;
$HeaderDoc::skiplist = "";
$HeaderDoc::idl_language = "idl";
$HeaderDoc::c_compiler = "/usr/bin/cc";
$HeaderDoc::debugAllocations = 0;
$HeaderDoc::newTOC = 0;
my @headerObjects; my @categoryObjects; my %objCClassNameToObject = (); my %headerIncluded = ();
%HeaderDoc::appleRefUsed = ();
%HeaderDoc::availability_defs = ();
%HeaderDoc::availability_has_args = ();
@HeaderDoc::exclude_patterns = ();
my @classObjects;
$HeaderDoc::fileDebug = 0;
$HeaderDoc::debugFile = "";
$HeaderDoc::CurLine = 0;
$| = 1;
my $uninstalledModulesPath;
my $devtoolsModulesPath;
BEGIN {
use FindBin qw ($Bin);
use Cwd;
use Getopt::Long;
use File::Find;
$HeaderDoc::parsing_man_pages = undef;
$HeaderDoc::headerObject = undef;
$HeaderDoc::testmode = undef;
$HeaderDoc::man_section = "3";
$HeaderDoc::lang = undef;
$HeaderDoc::sublang = undef;
$HeaderDoc::insert_header = 0;
$HeaderDoc::introductionName = "Introduction";
$HeaderDoc::auto_availability = 0;
$HeaderDoc::document_internal = 0;
$HeaderDoc::ExtraAppleWarnings = 0;
$HeaderDoc::ClassAsComposite = 0;
$HeaderDoc::AccessControlState = "";
$HeaderDoc::skipNextPDefine = 0;
%HeaderDoc::ignorePrefixes = ();
%HeaderDoc::perHeaderIgnorePrefixes = ();
%HeaderDoc::perHeaderIgnoreFuncMacros = ();
%HeaderDoc::filter_macro_definition_state = ();
%HeaderDoc::filter_macro_definition_value = ();
%HeaderDoc::perHeaderIncludes = ();
%HeaderDoc::perHeaderRanges = ();
$HeaderDoc::outerNamesOnly = 0;
%HeaderDoc::namerefs = ();
$HeaderDoc::uniquenumber = 0;
$HeaderDoc::specified_config_file = "";
$HeaderDoc::use_iframes = 1;
use lib '/Library/Perl/TechPubs'; use lib '/AppleInternal/Library/Perl';
my %options = ();
$HeaderDoc::groupright = 0;
$HeaderDoc::parse_javadoc = 0;
$HeaderDoc::force_parameter_tagging = 0;
$HeaderDoc::truncate_inline = 0;
$HeaderDoc::dumb_as_dirt = 1;
$HeaderDoc::add_link_requests = 1;
$HeaderDoc::suppress_local_variables = 0;
$HeaderDoc::use_styles = 0;
$HeaderDoc::ignore_apiuid_errors = 0;
$HeaderDoc::explicit_toc_format = undef;
$HeaderDoc::styleSheetExtras = undef;
$HeaderDoc::externalStyleSheets = undef;
$HeaderDoc::externalTOCStyleSheets = undef;
$HeaderDoc::styleImports = undef;
$HeaderDoc::tocStyleImports = undef;
$HeaderDoc::flagDashC = undef;
$HeaderDoc::sort_entries = undef;
$HeaderDoc::flagDashF = undef;
$HeaderDoc::maxDecLen = 60;
$HeaderDoc::superclassName = "Superclass";
$HeaderDoc::suppressDefaultJavaScript = 0;
$HeaderDoc::suppressDefaultStyles = 0;
if ($^O =~ /MacOS/io) {
$pathSeparator = ":";
$isMacOS = 1;
($uninstalledModulesPath = $FindBin::Bin) =~ s/([^:]*):$/$1/o;
} else {
$pathSeparator = "/";
$isMacOS = 0;
}
$uninstalledModulesPath = "$FindBin::Bin"."$pathSeparator"."Modules";
$devtoolsModulesPath = "$FindBin::Bin"."$pathSeparator".".."."$pathSeparator"."share"."$pathSeparator"."headerdoc"."$pathSeparator"."Modules";
foreach (qw(Mac::Files)) {
$MOD_AVAIL{$_} = eval "use $_; 1";
}
$HeaderDoc::twig_available = 0;
foreach my $path (@INC) {
my $name = $path.$pathSeparator."XML".$pathSeparator."Twig.pm";
if (-f $name) {
$HeaderDoc::twig_available = 1;
}
}
$HeaderDoc::FreezeThaw_available = 0;
foreach my $path (@INC) {
my $name = $path.$pathSeparator."FreezeThaw.pm";
if (-f $name) {
$HeaderDoc::FreezeThaw_available = 1;
}
}
}
use lib $uninstalledModulesPath;
use lib $devtoolsModulesPath;
use HeaderDoc::Utilities qw(linesFromFile getLangAndSubLangFromFilename dumpCaches stripLeading);
use HeaderDoc::Utilities qw(processTopLevel);
use locale;
Getopt::Long::Configure ("bundling", "no_ignore_case_always");
my $result = GetOptions(
"class-as-composite|C" => \$options{C},
"defined|D=s@" => \$options{D},
"process-everything|E" => \$options{E},
"old-style-frames|F" => \$options{F},
"insert-header|H" => \$options{H},
"suppress-local-variables|L" => \$options{L},
"man-section|M=s" => \$options{M},
"ignore-all-names|N" => \$options{N},
"outer-names-only|O" => \$options{O},
"pipe-output|P" => \$options{P},
"paranoid|Q" => \$options{Q},
"merge-superclass-docs|S" => \$options{S},
"test|T=s" => \$options{T},
"undefined|U=s@" => \$options{U},
"xml-output|X" => \$options{X},
"align-columns|a" => \$options{a},
"basic-processing-only|b" => \$options{b},
"config-file|c=s" => \$options{c},
"debugging|d" => \$options{d},
"exclude-list-file|e=s" => \$options{e},
"function-list-output|f" => \$options{f},
"group-right-side|g" => \$options{g},
"truncate-function-like-macros|i" => \$options{i},
"allow-javadoc-syntax|j" => \$options{j},
"no-link-requests|l" => \$options{l},
"man-page-output|m" => \$options{m},
"ignore-apiowner-names|n" => \$options{n},
"output-directory|o=s" => \$options{o},
"enable-cpp|p" => \$options{p},
"quiet|q" => \$options{q},
"strip|s" => \$options{s},
"enforce-strict-tagging|t" => \$options{t},
"unsorted|u" => \$options{u},
"version|v" => \$options{v},
"python-tab-width|w=i" => \$options{w},
"doxytags|x" => \$options{x},
"tocformat=s" => \$options{tocformat},
"auto-availability" => \$options{auto_availability},
"document-internal" => \$HeaderDoc::document_internal,
"apple" => \$options{apple}
);
if (!$result) {
die("Invalid options\n");
}
if ($options{d}) {
print STDERR "\tDebugging on...\n\n";
$debugging = 1;
}
if ($options{tocformat}) {
$HeaderDoc::explicit_toc_format = $options{tocformat};
}
if ($options{apple}) {
$options{auto_availability} = 1;
$options{H} = 1;
$options{j} = 1;
$options{n} = 1;
$options{N} = 1;
$options{p} = 1;
$options{O} = 1;
$options{Q} = 1;
$HeaderDoc::ExtraAppleWarnings = 1;
}
if ($options{auto_availability}) {
$HeaderDoc::auto_availability = 1;
}
if ($options{q}) {
$quietLevel = "1";
} else {
$quietLevel = "0";
}
if ($options{Q}) {
$HeaderDoc::enableParanoidWarnings = 1;
} else {
$HeaderDoc::enableParanoidWarnings = 0;
}
if ($options{v}) {
$printVersion = 1;
}
if ($options{r}) {
if ($HeaderDoc::twig_available) {
print STDERR "Regenerating headers.\n";
} else {
warn "***********************************************************************\n";
warn "* Headerdoc comment regeneration from XML requires XML::Parser *\n";
warn "* and XML::Twig, available from CPAN. Visit *\n";
warn "* *\n";
warn "* http://www.cpan.org *\n";
warn "* *\n";
warn "* for more information. *\n";
warn "***********************************************************************\n";
exit -1;
}
$regenerate_headers = 1;
} else {
$regenerate_headers = 0;
}
if ($options{F}) {
$HeaderDoc::use_iframes = 0;
$HeaderDoc::flagDashF = 1; }
if ($options{S}) {
$HeaderDoc::IncludeSuper = 1;
} else {
$HeaderDoc::IncludeSuper = 0;
}
if ($options{C} || $HeaderDoc::use_iframes) {
$HeaderDoc::ClassAsComposite = 1;
} else {
$HeaderDoc::flagDashC = -1; $HeaderDoc::ClassAsComposite = 0;
}
if ($options{E}) {
$HeaderDoc::process_everything = 1;
} else {
$HeaderDoc::process_everything = 0;
}
if ($options{D}) {
$HeaderDoc::enable_macro_filter = 1;
foreach my $symbol (@{$options{D}}) {
print STDERR "-D $symbol\n" if ($debugging);
if ($symbol =~ /=/) {
my @parts = split(/=/, $symbol);
$HeaderDoc::filter_macro_definition_state{$parts[0]} = 1;
$HeaderDoc::filter_macro_definition_value{$parts[0]} = $parts[1];
} else {
$HeaderDoc::filter_macro_definition_state{$symbol} = 1;
$HeaderDoc::filter_macro_definition_value{$symbol} = 1;
}
}
}
if ($options{U}) {
$HeaderDoc::enable_macro_filter = 1;
foreach my $symbol (@{$options{U}}) {
print STDERR "-U $symbol\n" if ($debugging);
if ($symbol =~ /=/) {
my @parts = split(/=/, $symbol);
$HeaderDoc::filter_macro_definition_state{$parts[0]} = -1;
$HeaderDoc::filter_macro_definition_value{$symbol} = "";
} else {
$HeaderDoc::filter_macro_definition_state{$symbol} = -1;
$HeaderDoc::filter_macro_definition_value{$symbol} = "";
}
}
}
if ($options{a}) {
$HeaderDoc::align_columns = 1;
} else {
$HeaderDoc::align_columns = 0;
}
if ($options{b}) {
$HeaderDoc::dumb_as_dirt = 1;
} else {
$HeaderDoc::dumb_as_dirt = 0;
}
if ($options{c}) {
$HeaderDoc::specified_config_file = $options{c};
}
if ($options{g}) {
$HeaderDoc::groupright = 1;
}
if ($options{j}) {
$HeaderDoc::parse_javadoc = 1;
}
if ($options{p}) {
$HeaderDoc::enable_cpp = 1;
} else {
$HeaderDoc::enable_cpp = 0;
}
if ($options{N}) {
$HeaderDoc::ignore_apiowner_names = 2;
} elsif ($options{n}) {
$HeaderDoc::ignore_apiowner_names = 1;
} else {
$HeaderDoc::ignore_apiowner_names = 0;
}
if ($options{l}) {
$HeaderDoc::add_link_requests = 0;
} else {
$HeaderDoc::add_link_requests = 1;
}
if ($options{L}) {
$HeaderDoc::suppress_local_variables = 1;
} else {
$HeaderDoc::suppress_local_variables = 0;
}
if ($options{M}) {
$HeaderDoc::man_section = $options{M};
} else {
$HeaderDoc::man_section = 3;
}
if ($options{m}) {
$man_output = 1;
$xml_output = 1;
} else {
$man_output = 0;
}
if ($options{e}) {
my $exclude_list_file = $options{e};
print STDERR "EXCLUDE LIST FILE is \"$exclude_list_file\". CWD is ".cwd()."\n" if (!$quietLevel);
my ($encoding, $linesref) = linesFromFile($exclude_list_file, 0);
my @templines = @{$linesref};
@HeaderDoc::exclude_patterns = ();
foreach my $line (@templines) {
$line =~ s/\n//g;
push(@HeaderDoc::exclude_patterns, $line);
}
} else {
@HeaderDoc::exclude_patterns = ();
}
if ($options{s}) {
$headerdoc_strip = 1;
} else {
$headerdoc_strip = 0;
}
if ($options{i}) {
$HeaderDoc::truncate_inline = 0;
} else {
$HeaderDoc::truncate_inline = 1;
}
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{w}) {
$HeaderDoc::python_tab_spaces = $options{w};
if (!$quietLevel) {
print STDERR "Python tab spaces set to ".$HeaderDoc::python_tab_spaces.".\n";
}
}
if ($options{t}) {
if (!$quietLevel) {
print STDERR "Forcing strict parameter tagging.\n";
}
$HeaderDoc::force_parameter_tagging = 1;
}
if ($options{T}) {
if (!$HeaderDoc::FreezeThaw_available) {
warn "FreezeThaw Perl module not found in library path. Please\n";
warn "install FreezeThaw and try again.\n";
exit -1;
}
$HeaderDoc::testmode = $options{T};
}
if ($options{O}) {
$HeaderDoc::outerNamesOnly = 1;
} else {
$HeaderDoc::outerNamesOnly = 0;
}
if ($options{o}) {
if ($use_stdout) {
die("-o and -P are mutually exclusive.");
}
$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 STDERR "\nDocumentation will be written to $specifiedOutputDir\n";
}
}
my $scriptDir = cwd();
$use_stdout = 0;
if (!$headerdoc_strip && !$man_output) {
if ($options{X}) {
print STDERR "XML output mode.\n" if ($quietLevel eq "0");
$xml_output = 1;
} elsif ($options{x}) {
print STDERR "Doxygen tagfile output mode.\n" if ($quietLevel eq "0");
$doxytag_output = 1;
if ($use_stdout) {
die("-o and -x are mutually exclusive\n");
}
} elsif ($options{f}) {
print STDERR "FUNCTION LIST output mode.\n" if ($quietLevel eq "0");
$function_list_output = 1;
$use_stdout = 1;
} else {
print STDERR "HTML output mode.\n" if ($quietLevel eq "0");
$xml_output = 0;
}
}
if ($options{P} || $use_stdout) {
$use_stdout = 1;
if ($doxytag_output) {
die("-P and -x are mutually exclusive\n");
}
if (!$xml_output && !$function_list_output) {
printf STDERR "XML output (-X) implicitly enabled by -P flag.\n";
$xml_output = 1;
}
if (!$HeaderDoc::ClassAsComposite) {
printf STDERR "ClassAsComposite (-C) implicitly enabled by -P flag.\n";
$HeaderDoc::ClassAsComposite = 1;
}
}
if (!$HeaderDoc::testmode && !$printVersion) {
print STDERR "Will process one or more individual files.\n" if ($debugging);
foreach my $singleFile (@ARGV) {
if (-d $singleFile) {
print STDERR "DIR $singleFile\n";
my $inputDir = $singleFile;
if ($inputDir =~ /$pathSeparator$/) {
$inputDir =~ s|(.*)$pathSeparator$|$1|; }
if ( -f $inputDir.$pathSeparator."skiplist") {
my ($encoding, $arrayref) = linesFromFile($inputDir."/skiplist", 0);
my @skiplist = @{$arrayref};
foreach my $skipfile (@skiplist) {
if ($skipfile !~ /^\s*\ $skipfile =~ s/^\s+//sg;
$skipfile =~ s/\s+$//sg;
$HeaderDoc::skiplist .= $skipfile."\n";
print STDERR "Will skip $skipfile\n" if ($debugging);
}
}
}
if ($^O =~ /MacOS/io) {
find(\&getHeaders, $inputDir);
} else {
&find({wanted => \&getHeaders, follow => 1, follow_skip => 2}, $inputDir);
}
} elsif (-f $singleFile) {
if ($singleFile =~ /\.(cpp|c|C|h|m|M|i|hdoc|php|php\d|class|pas|p|java|j|jav|jsp|js|jscript|html|shtml|dhtml|htm|shtm|dhtm|pl|pm|bsh|csh|ksh|sh|defs|idl|conf|rb|rbx|rhtml|ruby|py|pyw|applescript|scpt|tcl)$/o) {
push(@inputFiles, $singleFile);
} else {
warn "File $singleFile is not of a known header or source code file type\n";
}
} else {
warn "HeaderDoc: file/directory not found: $singleFile\n";
}
}
if ($debugging) {
foreach my $if (@inputFiles) {
print STDERR "FILE: $if\n";
}
}
unless (@inputFiles) {
print STDERR "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 getDoxyTagFiles {
my $filePath = $File::Find::name;
my $fileName = $_;
if ($fileName =~ /\.doxytagtemp$/o) {
push(@doxyTagFiles, $filePath);
}
}
sub getHeaders {
my $filePath = $File::Find::name;
my $fileName = $_;
if ($fileName =~ /\.(cpp|c|C|h|m|M|i|hdoc|php|php\d|class|pas|p|java|j|jav|jsp|js|jscript|html|shtml|dhtml|htm|shtm|dhtm|pl|pm|bsh|csh|ksh|sh|defs|idl|conf|rb|rbx|rhtml|ruby|py|pyw|applescript|scpt|tcl)$/o) {
if ($HeaderDoc::skiplist =~ /^\s*\Q$fileName\E\s*$/m) {
print STDERR "skipped $filePath\n";
} elsif (in_exclude_list($filePath)) {
print STDERR "skipped $filePath (found in exclude list)\n";
} else {
push(@inputFiles, $filePath);
}
}
}
sub in_exclude_list($)
{
my $filepath = shift;
foreach my $pattern (@HeaderDoc::exclude_patterns) {
if ($pattern =~ /\S/) {
if ($filepath =~ $pattern) {
return 1;
}
}
}
return 0;
}
use strict;
use File::Copy;
use File::Basename;
use lib $uninstalledModulesPath;
use HeaderDoc::Utilities qw(linesFromFile emptyHDok addAvailabilityMacro);
use HeaderDoc::Utilities qw(findRelativePath safeName
printArray linesFromFile printHash
updateHashFromConfigFiles getHashFromConfigFile
parseTokens
stringToFields warnHDComment validTag
filterHeaderDocComment processHeaderComment
getLineArrays resolveLink objectForUID getAbsPath
allow_everything getAvailabilityMacros);
use HeaderDoc::BlockParse qw(blockParseOutside getAndClearCPPHash cpp_add_cl);
use HeaderDoc::Header;
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::Group;
use HeaderDoc::MinorAPIElement;
use HeaderDoc::HashObject;
use HeaderDoc::ParseTree;
use HeaderDoc::ParserState;
use HeaderDoc::IncludeHash;
use HeaderDoc::Dependency;
use HeaderDoc::LineRange;
use HeaderDoc::AvailHelper;
use HeaderDoc::Test;
use HeaderDoc::MacroFilter;
$HeaderDoc::modulesPath = $INC{'HeaderDoc/ParseTree.pm'};
$HeaderDoc::modulesPath =~ s/ParseTree.pm$//so;
$HeaderDoc::testdir = $HeaderDoc::modulesPath."/../../testsuite";
$HeaderDoc::local_tests = 1;
if ( ! -d $HeaderDoc::testdir ) {
$HeaderDoc::local_tests = 0;
$HeaderDoc::testdir = "/usr/share/headerdoc/testsuite";
}
if ($printVersion) {
&printVersionInfo();
exit $HeaderDoc::exitstatus;
}
if ($HeaderDoc::testmode) {
print STDERR "Running tests.\n";
if ($HeaderDoc::testmode eq "create") {
newtest();
} else {
runtests($HeaderDoc::testmode, \@ARGV);
}
exit $HeaderDoc::exitstatus;
}
my $localConfigFileName = "headerDoc2HTML.config";
my $preferencesConfigFileName = "com.apple.headerDoc2HTML.config";
my $homeDir;
my $usersPreferencesPath;
my $systemPreferencesPath;
my $usersAppSupportPath;
my $systemAppSupportPath;
$HeaderDoc::custom_tags = undef;
if ($^O =~ /MacOS/io) {
eval
{
require "FindFolder.pl";
$homeDir = MacPerl::FindFolder("D"); $usersPreferencesPath = MacPerl::FindFolder("P"); $usersAppSupportPath = MacPerl::FindFolder("P"); };
if ($@) {
import Mac::Files;
$homeDir = Mac::Files::FindFolder(kOnSystemDisk(), kDesktopFolderType());
$usersPreferencesPath = Mac::Files::FindFolder(kOnSystemDisk(), kPreferencesFolderType());
$usersAppSupportPath = Mac::Files::FindFolder(kOnSystemDisk(), kPreferencesFolderType());
}
$systemPreferencesPath = $usersPreferencesPath;
$systemAppSupportPath = $usersAppSupportPath;
} else {
$homeDir = (getpwuid($<))[7];
$usersPreferencesPath = $homeDir.$pathSeparator."Library".$pathSeparator."Preferences";
$usersAppSupportPath = $homeDir.$pathSeparator."Library".$pathSeparator."Application Support".$pathSeparator."Apple".$pathSeparator."HeaderDoc";
$systemPreferencesPath = "/Library/Preferences";
$systemAppSupportPath = "/Library/Application Support/Apple/HeaderDoc";
}
my $devtoolsPreferencesPath = "$FindBin::Bin"."$pathSeparator".".."."$pathSeparator"."share"."$pathSeparator"."headerdoc"."$pathSeparator"."conf";
my $CWD = cwd();
my @configFiles = ($devtoolsPreferencesPath.$pathSeparator.$preferencesConfigFileName, $systemPreferencesPath.$pathSeparator.$preferencesConfigFileName, $usersPreferencesPath.$pathSeparator.$preferencesConfigFileName, $Bin.$pathSeparator.$localConfigFileName, $CWD.$pathSeparator.$localConfigFileName);
if (length($HeaderDoc::specified_config_file)) {
@configFiles = ();
push(@configFiles, $HeaderDoc::specified_config_file);
}
my %config = (
ignorePrefixes => "",
externalStyleSheets => "",
externalTOCStyleSheets => "",
tocStyleImports => "",
styleSheetExtrasFile => "",
styleImports => "",
TOCFormat => "default",
classAsComposite => $HeaderDoc::ClassAsComposite,
copyrightOwner => "",
defaultFrameName => "index.html",
compositePageName => "CompositePage.html",
masterTOCName => "MasterTOC.html",
apiUIDPrefix => "apple_ref",
htmlHeader => "",
htmlFooter => "",
htmlHeaderFile => "",
htmlFooterFile => "",
dateFormat => "",
textStyle => "",
commentStyle => "",
preprocessorStyle => "",
funcNameStyle => "",
stringStyle => "",
charStyle => "",
numberStyle => "",
keywordStyle => "",
typeStyle => "",
paramStyle => "",
varStyle => "",
templateStyle => "",
wrapAtColumn => "",
introductionName => "Introduction",
superclassName => "Superclass",
IDLLanguage => "idl",
cCompiler => "/usr/bin/cc"
);
%config = &updateHashFromConfigFiles(\%config,\@configFiles);
if ( -f $HeaderDoc::modulesPath."../../Availability.list") {
getAvailabilityMacros($HeaderDoc::modulesPath."../../Availability.list", 1);
} else {
getAvailabilityMacros($HeaderDoc::modulesPath."Availability.list", $quietLevel);
}
if ($config{"ignorePrefixes"}) {
my $localDebug = 0;
my @prefixlist = split(/\|/, $config{"ignorePrefixes"});
foreach my $prefix (@prefixlist) {
print STDERR "ignoring $prefix\n" if ($localDebug);
$prefix =~ s/^\s*//so;
$prefix =~ s/\s*$//so;
$HeaderDoc::ignorePrefixes{$prefix} = $prefix;
}
}
if ($config{"customTags"}) {
my %arr = ();
foreach my $tag (split(/\s+/, $config{"customTags"})) {
if (length($tag)) {
$arr{$tag} = 1;
}
}
$HeaderDoc::custom_tags = \%arr;
}
if (defined $config{bareNamesFromAPIRefs}) {
$HeaderDoc::nameFromAPIRefReturnsOnlyName = $config{bareNamesFromAPIRefs};
}
if ($config{"wrapAtColumn"}) {
$HeaderDoc::maxDecLen = $config{"wrapAtColumn"};
}
if ($config{"externalStyleSheets"}) {
$HeaderDoc::externalStyleSheets = $config{"externalStyleSheets"};
$HeaderDoc::externalStyleSheets =~ s/[\n\r]/ /sgo;
$HeaderDoc::use_styles = 1;
}
if ($config{"externalTOCStyleSheets"}) {
$HeaderDoc::externalTOCStyleSheets = $config{"externalTOCStyleSheets"};
$HeaderDoc::externalTOCStyleSheets =~ s/[\n\r]/ /sgo;
$HeaderDoc::use_styles = 1;
}
if ($config{"tocStyleImports"}) {
$HeaderDoc::tocStyleImports = $config{"tocStyleImports"};
$HeaderDoc::tocStyleImports =~ s/[\n\r]/ /sgo;
$HeaderDoc::use_styles = 1;
}
if (defined $config{"suppressDefaultStyles"}) {
if ($config{"suppressDefaultStyles"} eq "1" ||
$config{"suppressDefaultStyles"} eq "true") {
$HeaderDoc::suppressDefaultStyles = 1;
} else {
$HeaderDoc::suppressDefaultStyles = 0;
}
}
if (defined $config{"suppressDefaultJavaScript"}) {
if ($config{"suppressDefaultJavaScript"} eq "1" ||
$config{"suppressDefaultJavaScript"} eq "true") {
$HeaderDoc::suppressDefaultJavaScript = 1;
} else {
$HeaderDoc::suppressDefaultJavaScript = 0;
}
}
if ($config{"idlLanguage"}) {
$HeaderDoc::idl_language = $config{"idlLanguage"};
} elsif ($config{"IDLLanguage"}) {
$HeaderDoc::idl_language = $config{"IDLLanguage"};
}
if ($config{"cCompiler"}) {
$HeaderDoc::c_compiler = $config{"cCompiler"};
}
if ($config{"styleSheetExtrasFile"} ne "") {
my $found = 0;
my $basename = $config{"styleSheetExtrasFile"};
my $oldRS = $/;
$/ = undef;
my @extrasFiles = ($devtoolsPreferencesPath.$pathSeparator.$basename, $systemPreferencesPath.$pathSeparator.$basename, $usersPreferencesPath.$pathSeparator.$basename, $Bin.$pathSeparator.$basename, $CWD.$pathSeparator.$basename, $usersAppSupportPath.$pathSeparator.$basename, $systemAppSupportPath.$pathSeparator.$basename);
foreach my $filename (@extrasFiles) {
if (open(READFILE, "<$filename")) {
$HeaderDoc::styleSheetExtras = <READFILE>;
close(READFILE);
$found = 1;
}
}
$/ = $oldRS;
if (!$found) {
die("Could not find file $basename in expected locations.\n");
}
$HeaderDoc::styleSheetExtras =~ s/[\n\r]/ /sgo;
$HeaderDoc::use_styles = 1;
}
if ($config{"styleImports"}) {
$HeaderDoc::styleImports = $config{"styleImports"};
$HeaderDoc::styleImports =~ s/[\n\r]/ /sgo;
$HeaderDoc::use_styles = 1;
}
if (defined $config{"appleTOC"}) {
$HeaderDoc::newTOC = $config{"appleTOC"};
$HeaderDoc::newTOC =~ s/\s*//;
} else {
if (defined $config{"TOCFormat"}) {
setTOCFormat($config{"TOCFormat"});
} else {
$HeaderDoc::newTOC = 0;
}
}
if ($HeaderDoc::explicit_toc_format) {
setTOCFormat($HeaderDoc::explicit_toc_format);
}
if ($config{"classAsComposite"}) {
$HeaderDoc::ClassAsComposite = $config{"classAsComposite"};
$HeaderDoc::ClassAsComposite =~ s/\s*//;
} else {
$HeaderDoc::ClassAsComposite = 0;
}
if ($config{"copyrightOwner"}) {
HeaderDoc::APIOwner->copyrightOwner($config{"copyrightOwner"});
}
if ($config{"defaultFrameName"}) {
HeaderDoc::APIOwner->defaultFrameName($config{"defaultFrameName"});
}
if ($config{"compositePageName"}) {
HeaderDoc::APIOwner->compositePageName($config{"compositePageName"});
}
if ($config{"apiUIDPrefix"}) {
HeaderDoc::APIOwner->apiUIDPrefix($config{"apiUIDPrefix"});
}
if ($config{"htmlHeader"}) {
HeaderDoc::APIOwner->htmlHeader($config{"htmlHeader"});
}
if ($config{"htmlFooter"}) {
HeaderDoc::APIOwner->htmlFooter($config{"htmlFooter"});
}
my $oldRecSep = $/;
undef $/;
if ($config{"htmlHeaderFile"}) {
my $basename = $config{"htmlHeaderFile"};
my @htmlHeaderFiles = ($Bin.$pathSeparator.$basename, $usersPreferencesPath.$pathSeparator.$basename, $basename);
foreach my $filename (@htmlHeaderFiles) {
if (open(HTMLHEADERFILE, "<$filename")) {
my $headerString = <HTMLHEADERFILE>;
close(HTMLHEADERFILE);
HeaderDoc::APIOwner->htmlHeader($headerString);
}
}
}
if ($config{"htmlFooterFile"}) {
my $basename = $config{"htmlFooterFile"};
my @htmlFooterFiles = ($Bin.$pathSeparator.$basename, $usersPreferencesPath.$pathSeparator.$basename, $basename);
foreach my $filename (@htmlFooterFiles) {
if (open(HTMLFOOTERFILE, "<$filename")) {
my $headerString = <HTMLFOOTERFILE>;
close(HTMLFOOTERFILE);
HeaderDoc::APIOwner->htmlFooter($headerString);
}
}
}
$/ = $oldRecSep;
if ($config{"dateFormat"}) {
$HeaderDoc::datefmt = $config{"dateFormat"};
if ($HeaderDoc::datefmt !~ /\S/) {
$HeaderDoc::datefmt = "%B %d, %Y";
}
} else {
$HeaderDoc::datefmt = "%B %d, %Y";
}
HeaderDoc::APIOwner::fix_date("UTF-8");
if ($config{"textStyle"}) {
HeaderDoc::APIOwner->setStyle("text", $config{"textStyle"});
}
if ($config{"commentStyle"}) {
HeaderDoc::APIOwner->setStyle("comment", $config{"commentStyle"});
}
if ($config{"preprocessorStyle"}) {
HeaderDoc::APIOwner->setStyle("preprocessor", $config{"preprocessorStyle"});
}
if ($config{"funcNameStyle"}) {
HeaderDoc::APIOwner->setStyle("function", $config{"funcNameStyle"});
}
if ($config{"stringStyle"}) {
HeaderDoc::APIOwner->setStyle("string", $config{"stringStyle"});
}
if ($config{"charStyle"}) {
HeaderDoc::APIOwner->setStyle("char", $config{"charStyle"});
}
if ($config{"numberStyle"}) {
HeaderDoc::APIOwner->setStyle("number", $config{"numberStyle"});
}
if ($config{"keywordStyle"}) {
HeaderDoc::APIOwner->setStyle("keyword", $config{"keywordStyle"});
}
if ($config{"typeStyle"}) {
HeaderDoc::APIOwner->setStyle("type", $config{"typeStyle"});
}
if ($config{"paramStyle"}) {
HeaderDoc::APIOwner->setStyle("param", $config{"paramStyle"});
}
if ($config{"varStyle"}) {
HeaderDoc::APIOwner->setStyle("var", $config{"varStyle"});
}
if ($config{"templateStyle"}) {
HeaderDoc::APIOwner->setStyle("template", $config{"templateStyle"});
}
if ($config{"addToCustomReferenceStyle"}) {
HeaderDoc::APIOwner->setStyle("addToCustomReference", $config{"addToCustomReferenceStyle"});
}
if ($config{"addToCustomReferenceLinkStyle"}) {
HeaderDoc::APIOwner->setStyle("addToCustomReferenceLink", $config{"addToCustomReferenceLinkStyle"});
}
if ($config{"introductionName"}) {
$HeaderDoc::introductionName=$config{"introductionName"};
}
if ($config{"superclassName"}) {
$HeaderDoc::superclassName=$config{"superclassName"};
}
my $inHeader = 0;
my $inJavaSource = 0;
my $inShellScript = 0;
my $inPerlScript = 0;
my $inPHPScript = 0;
my $inCPPHeader = 0;
my $inOCCHeader = 0;
my $inClass = 0; my $inInterface = 0;
my $inFunction = 0;
my $inAvailabilityMacro = 0;
my $inFunctionGroup = 0;
my $inGroup = 0;
my $inTypedef = 0;
my $inUnknown = 0;
my $inStruct = 0;
my $inUnion = 0;
my $inConstant = 0;
my $inVar = 0;
my $inPDefine = 0;
my $inEnum = 0;
my $inMethod = 0;
my $rootFileName;
%HeaderDoc::HeaderFileCPPHashHash = ();
%HeaderDoc::HeaderFileCPPArgHashHash = ();
my $includeDebug = 0;
if (!$quietLevel) {
print STDERR "======= Parsing Input Files =======\n";
}
if ($use_stdout && (scalar(@inputFiles) > 1)) {
die("-P flag limits you to a single input file.\n");
}
if ($debugging) { print STDERR "Processing includes.\n"; }
foreach my $inputFile (@inputFiles) {
my $fullpath=getAbsPath($inputFile);
my ($rootFileName, $lang, $sublang) = getLangAndSubLangFromFilename($inputFile);
my $headerObject = HeaderDoc::Header->new("LANG" => $lang, "SUBLANG" => $sublang);
$HeaderDoc::headerObject = $headerObject;
my ($encoding, $arrayref) = linesFromFile($inputFile, 1);
my @rawInputLines = @{$arrayref};
if ($debugging) { print STDERR "Checking file $inputFile\n"; }
processIncludes(\@rawInputLines, $fullpath, $lang, $sublang);
}
if ($debugging) { print STDERR "Done processing includes. Fixing dependencies.\n"; }
my @fileList = ();
if (1 || $HeaderDoc::enable_cpp) {
my $deplistref = fix_dependency_order(\@inputFiles);
if ($deplistref) {
@fileList = @{$deplistref};
} else {
@fileList = @inputFiles;
}
} else {
@fileList = @inputFiles
}
if ($debugging) { print STDERR "Done fixing dependencies. Filling fileList hash.\n"; }
if ($#fileList != $#inputFiles) {
die("File counts don't match: ".$#fileList." != ".$#inputFiles.".\n");
}
my %filelisthash = ();
my @oldfileList = @fileList;
@fileList = ();
foreach my $inputFile (@oldfileList) {
if (!$filelisthash{$inputFile}) {
$filelisthash{$inputFile} = 1;
push(@fileList, $inputFile);
}
}
if ($debugging) { print STDERR "Done filling fileList hash\n"; }
@oldfileList = (); %filelisthash = ();
my $sort_entries = $HeaderDoc::sort_entries;
my $tlhangDebug = 0;
foreach my $inputFile (@fileList) {
my $headerObject; my $cppAccessControlState = "protected:"; my $objcAccessControlState = "private:"; $HeaderDoc::AccessControlState = "";
my $hashtreecur = undef;
my $hashtreeroot = undef;
my @perHeaderClassObjects = ();
my @perHeaderCategoryObjects = ();
$HeaderDoc::sort_entries = $sort_entries;
my @path = split (/$pathSeparator/, $inputFile);
my $filename = pop (@path);
if ($HeaderDoc::HeaderFileCPPHashHash{$inputFile}) {
print STDERR "Already procesed $inputFile. Skipping.\n" if ($includeDebug);
next;
}
if (basename($filename) eq $HeaderDoc::debugFile) {
$HeaderDoc::fileDebug = 1;
print STDERR "Enabling debug mode for this file.\n";
}
print STDERR "Top Level Point 100\n" if ($tlhangDebug);
my $sublang = "";
if ($quietLevel eq "0") {
if ($headerdoc_strip) {
print STDERR "\nStripping $inputFile\n";
} elsif ($regenerate_headers) {
print STDERR "\nRegenerating $inputFile\n";
} else {
print STDERR "\nProcessing $inputFile\n";
}
}
%HeaderDoc::perHeaderIgnorePrefixes = ();
foreach my $predefined_token (keys %HeaderDoc::filter_macro_definition_state) {
if ($HeaderDoc::filter_macro_definition_state{$predefined_token} == 1) {
cpp_add_cl($predefined_token, $HeaderDoc::filter_macro_definition_value{$predefined_token});
}
}
$HeaderDoc::globalGroup = "";
$reprocess_input = 0;
my $headerDir = join("$pathSeparator", @path);
print STDERR "Top Level Point 200\n" if ($tlhangDebug);
($rootFileName, $lang, $sublang) = getLangAndSubLangFromFilename($filename);
if ($sublang eq "IDL") {
$cppAccessControlState = "public:"; }
$HeaderDoc::OptionalOrRequired = "";
my $rootOutputDir;
if (length ($specifiedOutputDir)) {
$rootOutputDir ="$specifiedOutputDir$pathSeparator$rootFileName";
} elsif (@path) {
$rootOutputDir ="$headerDir$pathSeparator$rootFileName";
} else {
$rootOutputDir = $rootFileName;
}
my $localDebug = 0;
$headerObject = HeaderDoc::Header->new("LANG" => $lang, "SUBLANG" => $sublang);
$HeaderDoc::headerObject = $headerObject;
my ($encoding, $arrayref) = linesFromFile($inputFile, 1);
my @rawInputLines = @{$arrayref};
print STDERR "ENCODING GUESS: $encoding\n" if ($localDebug);
@HeaderDoc::cppHashList = ();
@HeaderDoc::cppArgHashList = ();
REDO:
print STDERR "Top Level Point 300\n" if ($tlhangDebug);
print STDERR "REDO" if ($debugging);
my @headerDocCommentLines = grep(/^\s*\/\*\!/, @rawInputLines);
if ((!@headerDocCommentLines) && ($lang eq "java" || $HeaderDoc::parse_javadoc)) {
@headerDocCommentLines = grep(/^\s*\/\*\*[^\*]/, @rawInputLines);
}
if ((!@headerDocCommentLines) && ($lang eq "ruby" || $lang eq "python")) {
@headerDocCommentLines = grep(/^\s*\!headerdoc\!\s*$/i, @rawInputLines);
}
if ((!@headerDocCommentLines) && ($lang eq "perl" || $lang eq "shell" ||
$lang eq "tcl")) {
@headerDocCommentLines = grep(/^\s*\ }
if ((!@headerDocCommentLines) && ($lang eq "pascal")) {
@headerDocCommentLines = grep(/^\s*\{\!/, @rawInputLines);
}
if ((!@headerDocCommentLines) && ($lang eq "applescript")) {
@headerDocCommentLines = grep(/^\s*\(\*\!/, @rawInputLines);
}
my $skip_header_processing = 0;
if (!@headerDocCommentLines && ((!$HeaderDoc::process_everything) || (!allow_everything($lang, $sublang)))) {
if ($quietLevel eq "0") {
print STDERR " Skipping. No HeaderDoc comments found.\n";
$skip_header_processing = 1;
}
}
my $fullpath=getAbsPath($inputFile);
my $basefilename = basename($inputFile);
print STDERR "Top Level Point 400\n" if ($tlhangDebug);
if (!$headerdoc_strip) {
$headerObject->encoding($encoding);
$headerObject->linenuminblock(0);
$headerObject->blockoffset(0);
$headerObject->apiOwner($headerObject);
$HeaderDoc::headerObject = $headerObject;
if ($use_stdout) {
$headerObject->use_stdout(1);
} else {
$headerObject->use_stdout(0);
}
if ($xml_output) {
$headerObject->outputformat("hdxml");
} elsif ($function_list_output) {
$headerObject->outputformat("functions");
} else {
$headerObject->outputformat("html");
}
$headerObject->outputDir($rootOutputDir);
$headerObject->name($filename);
$headerObject->filename($filename);
$headerObject->fullpath($fullpath);
} else {
$HeaderDoc::headerObject = $headerObject;
if ($use_stdout) {
$headerObject->use_stdout(1);
} else {
$headerObject->use_stdout(0);
}
$headerObject->filename($filename);
$headerObject->linenuminblock(0);
$headerObject->blockoffset(0);
}
print STDERR "Top Level Point 500\n" if ($tlhangDebug);
my @lineArrays = &getLineArrays(\@rawInputLines, $lang, $sublang);
my $processEverythingDebug = 0;
my $localDebug = 0 || $debugging;
my $linenumdebug = 0;
print STDERR "Top Level Point 600\n" if ($tlhangDebug);
if ($headerdoc_strip) {
my $outdir = "";
if (length ($specifiedOutputDir)) {
$outdir ="$specifiedOutputDir";
} elsif (@path) {
$outdir ="$headerDir";
} else {
$outdir = "strip_output";
}
strip($filename, $outdir, $rootOutputDir, $inputFile, \@rawInputLines);
print STDERR "done.\n" if ($quietLevel eq "0");
next;
}
if ($regenerate_headers) {
HeaderDoc::Regen->regenerate($inputFile, $rootOutputDir);
print STDERR "done.\n" if ($quietLevel eq "0");
next;
}
print STDERR "Top Level Point 700\n" if ($tlhangDebug);
my $retainheader = 0;
if (!$skip_header_processing) {
foreach my $arrayRef (@lineArrays) {
my $blockOffset = 0;
my @inputLines = @$arrayRef;
$cppAccessControlState = "protected:"; $objcAccessControlState = "private:";
if ($sublang eq "IDL") {
$cppAccessControlState = "public:"; }
$HeaderDoc::AccessControlState = "";
print STDERR "Top Level Point 705\n" if ($tlhangDebug);
my $parseTokensRef = parseTokens($lang, $sublang);
my $apiOwner = $headerObject; my ($case_sensitive, $keywordhashref) = $apiOwner->keywords();
$HeaderDoc::currentClass = $apiOwner;
print STDERR "Top Level Point 710\n" if ($tlhangDebug);
print STDERR "inHeader\n" if ($localDebug);
my $inputCounter = 0;
my $ctdebug = 0;
my $classType = "unknown";
print STDERR "CLASS TYPE CHANGED TO $classType\n" if ($ctdebug);
my $nlines = $#inputLines;
print STDERR "PROCESSING LINE ARRAY\n" if ($HeaderDoc::inputCounterDebug);
my $inMLC = 0;
print STDERR "Top Level Point 715\n" if ($tlhangDebug);
while ($inputCounter <= $nlines) {
my $line = "";
print STDERR "LINE: \"".$inputLines[$inputCounter]."\"\n" if ($localDebug || $includeDebug);
if ($inputLines[$inputCounter] =~ /^\s* print STDERR "Include line: $1\n" if ($includeDebug);
my $rest = $1;
$rest =~ s/^\s*//s;
$rest =~ s/\s*$//s;
if ($rest !~ s/^\<(.*)\>$/$1/s) {
$rest =~ s/^\"(.*)\"$/$1/s;
}
my $filename = basename($rest);
if ($HeaderDoc::HeaderFileCPPHashHash{$filename}) {
my $includehash = HeaderDoc::IncludeHash->new();
$includehash->{FILENAME} = $filename;
$includehash->{LINENUM} = $inputCounter + $blockOffset;
$includehash->{HASHREF} = $HeaderDoc::HeaderFileCPPHashHash{$filename};
push(@HeaderDoc::cppHashList, $includehash);
push(@HeaderDoc::cppArgHashList, $HeaderDoc::HeaderFileCPPArgHashHash{$filename});
print STDERR "Adding include for $filename.\n" if ($includeDebug);
}
}
print STDERR "Input line number[1]: $inputCounter\n" if ($localDebug);
print STDERR "last line ".$inputLines[$inputCounter-1]."\n" if ($localDebug);
print STDERR "next line ".$inputLines[$inputCounter]."\n" if ($localDebug);
if ($inputLines[$inputCounter] =~ /^\s*(public|private|protected)/o) {
$cppAccessControlState = $&;
if ($inputLines[$inputCounter] =~ /^\s*(public|private|protected)\s*:/o) {
$cppAccessControlState =~ s/^\s+//o;
$cppAccessControlState =~ s/\s*:\s*$/$1/so;
$cppAccessControlState = "$cppAccessControlState:";
}
}
if ($inputLines[$inputCounter] =~ /^\s*(\@public|\@private|\@protected)/o) {
$objcAccessControlState = $&;
if ($inputLines[$inputCounter] =~ /^\s*(\@public|\@private|\@protected)\s+/o) {
$objcAccessControlState =~ s/^\s+//o;
$objcAccessControlState =~ s/\s*:\s*$/$1/so;
$objcAccessControlState = "$objcAccessControlState:";
}
}
print STDERR "Top Level Point 750\n" if ($tlhangDebug);
my @fields = ();
$HeaderDoc::allow_multi = 0;
if (($lang ne "pascal" && $lang ne "applescript" && $lang ne "ruby" && $lang ne "python" && (
($lang ne "perl" && $lang ne "shell" && $lang ne "tcl" && $inputLines[$inputCounter] =~ /^\s*\/\*\!/o) ||
(($lang eq "perl" || $lang eq "shell" || $lang eq "tcl") && ($inputLines[$inputCounter] =~ /^\s*\ (($lang eq "java" || $HeaderDoc::parse_javadoc) && ($inputLines[$inputCounter] =~ /^\s*\/\*\*[^*]/o)))) ||
(($lang eq "applescript") && ($inputLines[$inputCounter] =~ s/^\s*\(\*!/\/\*!/so)) ||
(($lang eq "pascal") && ($inputLines[$inputCounter] =~ s/^\s*\{!/\/\*!/so)) ||
(($lang eq "ruby" || $lang eq "python") && $inMLC && ($inputLines[$inputCounter] =~ s/\s*\!headerdoc\!\s*$/\/\*\!/iso))) { my $newlinecount = 0;
print STDERR "Top Level Point 755\n" if ($tlhangDebug);
if ($lang ne "ruby" &&
(($lang ne "pascal" && $lang ne "python" && $lang ne "applescript" && ($inputLines[$inputCounter] =~ /\s*\*\//o)) ||
($lang eq "python" && ($inputLines[$inputCounter] =~ /\"\"\".*\"\"\"/)) ||
($lang eq "applescript" && ($inputLines[$inputCounter] =~ s/\s*\*\)/\*\//so)) ||
($lang eq "pascal" && ($inputLines[$inputCounter] =~ s/\s*\}/\*\//so)))) { # closing comment marker on same line
my $linecopy = $inputLines[$inputCounter];
$newlinecount = ($linecopy =~ tr/\n//);
$blockOffset += $newlinecount - 1;
print STDERR "NEWLINECOUNT: $newlinecount\n" if ($linenumdebug);
print STDERR "BLOCKOFFSET: $blockOffset\n" if ($linenumdebug);
my $newline = $inputLines[$inputCounter++];
if ($lang eq "perl" || $lang eq "shell" || $lang eq "tcl") {
$newline = stripLeading($newline, "#"); }
if ($lang eq "python") {
$newline =~ s/\"\"\"/\/\*/s;
$newline =~ s/\"\"\"/\*\//s;
}
$line .= $newline;
print STDERR "INCREMENTED INPUTCOUNTER [M1]\n" if ($HeaderDoc::inputCounterDebug);
if (!emptyHDok($line)) {
warnHDComment(\@inputLines, $inputCounter, $blockOffset, $lang, "HeaderDoc comment", "1", $parseTokensRef, $line);
}
print STDERR "Input line number[2]: $inputCounter\n" if ($localDebug);
print STDERR "next line ".$inputLines[$inputCounter]."\n" if ($localDebug);
} else { my $nInputLines = $nlines;
print STDERR "MULTI-LINE LOOP START\n" if ($tlhangDebug);
do {
my $templine = $inputLines[$inputCounter];
my $newline = $inputLines[$inputCounter++];
print STDERR "INCREMENTED INPUTCOUNTER [M2]\n" if ($HeaderDoc::inputCounterDebug);
warnHDComment(\@inputLines, $inputCounter, $blockOffset, $lang, "HeaderDoc comment", "2", $parseTokensRef);
$newline =~ s/^ \*//o;
print STDERR "NEWLINE [A] IS $newline\n" if ($localDebug);
if ($lang eq "perl" || $lang eq "shell" || $lang eq "tcl") {
$newline = stripLeading($newline, "#"); }
$line .= $newline;
print STDERR "Input line number[3]: $inputCounter\n" if ($localDebug);
print STDERR "next line ".$inputLines[$inputCounter]."\n" if ($localDebug);
} while ((($lang eq "pascal" && ($inputLines[$inputCounter] !~ /\}/o)) ||
($lang eq "applescript" && ($inputLines[$inputCounter] !~ /\*\)/o)) ||
($lang eq "python" && ($inputLines[$inputCounter] !~ s/\"\"\"$/\*\//so)) ||
($lang eq "ruby" && ($inputLines[$inputCounter] !~ s/^=end\s*$/\*\//so)) ||
($lang ne "pascal" && $lang ne "ruby" && $lang ne "python" && $lang ne "applescript" && ($inputLines[$inputCounter] !~ s/\*\//\*\//so))) &&
($inputCounter <= $nInputLines));
print STDERR "MULTI-LINE LOOP END\n" if ($tlhangDebug);
$inMLC = 0;
my $newline = $inputLines[$inputCounter++];
print STDERR "INCREMENTED INPUTCOUNTER [M3]\n" if ($HeaderDoc::inputCounterDebug);
if (!emptyHDok($line)) {
my $dectype = "HeaderDoc comment";
if ($line =~ /^\s*\/\*\!\s*\@define(d)?block\s+/s) {
$dectype = "defineblock";
}
warnHDComment(\@inputLines, $inputCounter, $blockOffset, $lang, $dectype, "3", $parseTokensRef);
}
if ($lang eq "perl" || $lang eq "shell" || $lang eq "tcl") {
print STDERR "NEWLINE [B] IS $newline\n" if ($localDebug);
$newline = stripLeading($newline, "#"); }
if ($newline !~ /^ \*\//o) {
$newline =~ s/^ \*//o;
}
$line .= $newline; print STDERR "Input line number[4]: $inputCounter\n" if ($localDebug);
print STDERR "last line ".$inputLines[$inputCounter-1]."\n" if ($localDebug);
print STDERR "next line ".$inputLines[$inputCounter]."\n" if ($localDebug);
}
if (($lang eq "java" || $HeaderDoc::parse_javadoc) && ($line =~ /^\s*\/\*\*[^*]/o)) {
$line =~ s/^\s*\/\*\*/\/\*\!/o;
}
$line =~ s/^\s+//o; # trim leading whitespace
$line =~ s/^(.*)\*\/\s*$/$1/so;
print STDERR "CURRENT line \"$line\"\n" if ($localDebug);
($inHeader, $inClass, $inInterface, $inCPPHeader, $inOCCHeader, $inPerlScript, $inShellScript, $inPHPScript, $inJavaSource, $inFunctionGroup, $inGroup, $inFunction, $inPDefine, $inTypedef, $inUnion, $inStruct, $inConstant, $inVar, $inEnum, $inMethod, $inAvailabilityMacro, $inUnknown, $classType, $line, $inputCounter, $blockOffset, $filename, $linenumdebug, $localDebug) = processTopLevel($inHeader, $inClass, $inInterface, $inCPPHeader, $inOCCHeader, $inPerlScript, $inShellScript, $inPHPScript, $inJavaSource, $inFunctionGroup, $inGroup, $inFunction, $inPDefine, $inTypedef, $inUnion, $inStruct, $inConstant, $inVar, $inEnum, $inMethod, $inAvailabilityMacro, $inUnknown, $classType, $line, $inputCounter, $blockOffset, $inputFile, $linenumdebug, $localDebug);
my $linenum = $inputCounter - 1;
my $fieldref = stringToFields($line, $fullpath, $linenum, $xml_output, $lang, $sublang);
@fields = @{$fieldref};
$HeaderDoc::allow_multi = 1; } elsif ($HeaderDoc::process_everything && allow_everything($lang, $sublang)) {
print STDERR "Top Level Point 760\n" if ($tlhangDebug);
my ($tempInputCounter, $dec, $type, $name, $pt, $value, $pplref, $returntype, $pridec,
$parseTree, $simpleTDcontents, $bpavail) = &HeaderDoc::BlockParse::blockParse($fullpath, $blockOffset, \@inputLines,
$inputCounter, 0, \%HeaderDoc::ignorePrefixes, \%HeaderDoc::perHeaderIgnorePrefixes,
\%HeaderDoc::perHeaderIgnoreFuncMacros, $keywordhashref, $case_sensitive, $lang, $sublang);
print STDERR "Top Level Point 765\n" if ($tlhangDebug);
if ($dec !~ /^(\/\*.*?\*\/|\/\/.*?(\n|\r)|\n|\r)*(\/\*\!)/) {
print STDERR "DECLARATION WITH NO MARKUP ENCOUNTERED.\n" if ($processEverythingDebug);
$inUnknown = 1; } else {
print STDERR "DECLARATION WITH MARKUP ENCOUNTERED.\n" if ($processEverythingDebug);
}
$HeaderDoc::allow_multi = 0; @fields = ();
} elsif ($lang eq "python" && ($inputLines[$inputCounter] =~ /\"\"\"/o) && !$inMLC) {
$inMLC = 1;
} elsif ($lang eq "ruby" && ($inputLines[$inputCounter] =~ /^=begin\s*$/o)) {
$inMLC = 1;
} elsif ($lang eq "ruby" && ($inputLines[$inputCounter] =~ /^=end\s*$/o)) {
$inMLC = 0;
} print STDERR "Top Level Point 770\n" if ($tlhangDebug);
my $preAtPart = "";
if ($inCPPHeader) {print STDERR "inCPPHeader\n" if ($debugging); $sublang="cpp"; };
if ($inOCCHeader) {print STDERR "inCPPHeader\n" if ($debugging); $sublang="occ"; };
if ($inPerlScript) {print STDERR "inPerlScript\n" if ($debugging); $lang="php";};
if ($inPHPScript) {print STDERR "inPHPScript\n" if ($debugging); $lang="php";};
if ($inJavaSource) {print STDERR "inJavaSource\n" if ($debugging); $lang="java";};
if ($inHeader) {
print STDERR "inHeader\n" if ($debugging);
$functionGroup = "";
$HeaderDoc::globalGroup = "";
($lang, $sublang) = processHeaderComment($apiOwner, $rootOutputDir, \@fields, $debugging, \$reprocess_input, $lang, $sublang);
$HeaderDoc::currentClass = $apiOwner;
$inputCounter--;
print STDERR "DECREMENTED INPUTCOUNTER [M5]\n" if ($HeaderDoc::inputCounterDebug);
if ($reprocess_input == 1) {
my $localDebug = 0;
$reprocess_input = 2;
goto REDO;
}
};
if ($inGroup) {
print STDERR "inGroup\n" if ($debugging);
my $group = HeaderDoc::Group->new("LANG" => $lang, "SUBLANG" => $sublang);
$group->fullpath($fullpath);
$group->filename($filename);
$group->linenuminblock($inputCounter - 1);
$group->blockoffset(0);
$group->apiOwner($apiOwner);
$group = $group->processComment(\@fields);
$apiOwner->addGroup($group, 1);
$HeaderDoc::globalGroup = $group->name();
$inputCounter--;
print STDERR "DECREMENTED INPUTCOUNTER [M6]\n" if ($HeaderDoc::inputCounterDebug);
};
if ($inFunctionGroup) {
print STDERR "inFunctionGroup\n" if ($debugging);
my $group = HeaderDoc::Group->new("LANG" => $lang, "SUBLANG" => $sublang);
$group->filename($filename);
$group->linenuminblock($inputCounter - 1);
$group->blockoffset(0);
$group->apiOwner($apiOwner);
$group = $group->processComment(\@fields);
print STDERR "group name is ".$group->name()."\n" if ($debugging);
$apiOwner->addGroup($group, 0);
$functionGroup = $group->name();
$inputCounter--;
print STDERR "DECREMENTED INPUTCOUNTER [M7]\n" if ($HeaderDoc::inputCounterDebug);
};
print STDERR "Top Level Point 800\n" if ($tlhangDebug);
if ($inUnknown || $inTypedef || $inStruct || $inEnum || $inUnion || $inConstant || $inVar || $inFunction || $inMethod || $inPDefine || $inClass || $inAvailabilityMacro) {
my $hangDebug = 0;
my $parmDebug = 0;
my $blockDebug = 0;
print STDERR "Top Level Point 810\n" if ($tlhangDebug);
if ($inClass && $debugging) { print STDERR "INCLASS (MAIN)\n";
print STDERR "line is $line\n";
print STDERR "IC: $inputCounter\n";
print STDERR "CUR LINE: ".$inputLines[$inputCounter-1]."\n";
print STDERR "NEXT LINE: ".$inputLines[$inputCounter]."\n";
}
my $subparse = 0;
my $subparseTree = undef;
my $classref = undef;
my $catref = undef;
my $newInputCounter;
print STDERR "CALLING blockParseOutside WITH IC: $inputCounter (".$inputLines[$inputCounter].")\n" if ($debugging);
my $junk = undef;
print STDERR "BLOCKOFFSET IN LOOP: $blockOffset\n" if ($linenumdebug);
my $bpPrintDebug = $localDebug || 0;
print STDERR "Top Level Point 820\n" if ($tlhangDebug);
my $nodec = 0; print STDERR "my (\$newInputCounter, \$cppAccessControlState, \$classType, \$classref, \$catref, \$blockOffset, \$numcurlybraces, \$foundMatch, \$newlang, \$newsublang, \$hashtreecur, \$hashtreeroot) =
blockParseOutside($apiOwner, $inFunction, $inUnknown,
$inTypedef, $inStruct, $inEnum, $inUnion,
$inConstant, $inVar, $inMethod, $inPDefine,
$inClass, $inInterface, $blockOffset, \@perHeaderCategoryObjects
,
\@perHeaderClassObjects, $classType, $cppAccessControlState,
\@fields, $fullpath, $functionGroup,
$headerObject, $inputCounter, \@inputLines,
$lang, $nlines, $preAtPart, $xml_output, $localDebug,
$hangDebug, $parmDebug, $blockDebug, $subparse,
$subparseTree, $nodec, $HeaderDoc::allow_multi,
undef, $sublang, $hashtreecur, $hashtreeroot);\n" if ($bpPrintDebug || $tlhangDebug);
print STDERR "FIELDS:\n" if ($bpPrintDebug || $tlhangDebug);
printArray(@fields) if ($bpPrintDebug || $tlhangDebug);
print "FIRSTLINE: ".$inputLines[$inputCounter]."\n" if ($bpPrintDebug || $tlhangDebug);
my $foundMatch; my $newlang; my $newsublang;
($newInputCounter, $cppAccessControlState, $classType, $classref, $catref, $blockOffset, $junk, $foundMatch, $newlang, $newsublang, $hashtreecur, $hashtreeroot) =
blockParseOutside($apiOwner, $inFunction, $inUnknown,
$inTypedef, $inStruct, $inEnum, $inUnion,
$inConstant, $inVar, $inMethod, $inPDefine,
$inClass, $inInterface, $blockOffset, \@perHeaderCategoryObjects,
\@perHeaderClassObjects, $classType, $cppAccessControlState,
\@fields, $fullpath, $functionGroup,
$headerObject, $inputCounter, \@inputLines,
$lang, $nlines, $preAtPart, $xml_output, $localDebug,
$hangDebug, $parmDebug, $blockDebug, $subparse,
$subparseTree, $nodec, $HeaderDoc::allow_multi,
undef, $sublang, $hashtreecur, $hashtreeroot);
print STDERR "BLOCKOFFSET RETURNED: $blockOffset\n" if ($linenumdebug);
$lang = $newlang;
$sublang = $newsublang;
print STDERR "Top Level Point 830\n" if ($tlhangDebug);
@perHeaderClassObjects = @{$classref};
@perHeaderCategoryObjects = @{$catref};
print "IC: $inputCounter NIC: $newInputCounter\n" if ($HeaderDoc::inputCounterDebug);
$inputCounter = $newInputCounter;
if ($lang eq "perl" && $HeaderDoc::perlClassChange) {
print STDERR "CLASS: ".$HeaderDoc::perlClassChange."\n" if ($localDebug);
print STDERR "OLDAPIO: $apiOwner\n" if ($localDebug);
$apiOwner = $HeaderDoc::perlClassChange;
$HeaderDoc::perlClassChange = undef;
}
} print STDERR "Top Level Point 890\n" if ($tlhangDebug);
$inCPPHeader = $inOCCHeader = $inPerlScript = $inShellScript = $inPHPScript = $inJavaSource = $inInterface = $inHeader = $inUnknown = $inFunction = $inAvailabilityMacro = $inFunctionGroup = $inGroup = $inTypedef = $inUnion = $inStruct = $inConstant = $inVar = $inPDefine = $inEnum = $inMethod = $inClass = 0;
$inputCounter++;
print STDERR "INCREMENTED INPUTCOUNTER [M9] TO $inputCounter\n" if ($HeaderDoc::inputCounterDebug);
print STDERR "Input line number[8]: $inputCounter\n" if ($localDebug);
} print STDERR "Top Level Point 895\n" if ($tlhangDebug);
if ($lang eq "perl" && ($apiOwner != $headerObject)) {
print STDERR "Resetting Header Object\n" if ($localDebug);
$apiOwner = $headerObject;
}
print STDERR "DONE PROCESSING LINE ARRAY\n" if ($HeaderDoc::inputCounterDebug);
print STDERR "Top Level Point 900\n" if ($tlhangDebug);
if (ref($apiOwner) ne "HeaderDoc::Header") { my $name = $apiOwner->name();
my $refName = ref($apiOwner);
SWITCH: {
($classType eq "php" ) && do {
push (@perHeaderClassObjects, $apiOwner);
$headerObject->addToClasses($apiOwner);
last SWITCH; };
($classType eq "java" ) && do {
push (@perHeaderClassObjects, $apiOwner);
$headerObject->addToClasses($apiOwner);
last SWITCH; };
($classType eq "cpp" ) && do {
push (@perHeaderClassObjects, $apiOwner);
$headerObject->addToClasses($apiOwner);
last SWITCH; };
($classType eq "cppt" ) && do {
push (@perHeaderClassObjects, $apiOwner);
$headerObject->addToClasses($apiOwner);
last SWITCH; };
($classType eq "occ") && do {
push (@perHeaderClassObjects, $apiOwner);
if ($headerIncluded{$basefilename}) {
$retainheader = 1;
}
$headerObject->addToClasses($apiOwner);
$objCClassNameToObject{$apiOwner->name()} = $apiOwner;
last SWITCH; };
($classType eq "intf") && do {
push (@perHeaderClassObjects, $apiOwner);
$headerObject->addToProtocols($apiOwner);
last SWITCH;
};
($classType eq "occCat") && do {
push (@perHeaderCategoryObjects, $apiOwner);
print STDERR "INSERTED CATEGORY into $headerObject\n" if ($ctdebug);
$headerObject->addToCategories($apiOwner);
last SWITCH;
};
($classType eq "C") && do {
$cppAccessControlState = "";
push (@perHeaderClassObjects, $apiOwner);
$headerObject->addToClasses($apiOwner);
last SWITCH;
};
foreach my $testclassref ( $headerObject->classes() ) {
my $testclass = %{$testclassref};
bless($testclass, "HeaderDoc::APIOwner");
bless($testclass, $testclass->class());
print STDERR $testclass->name() . "\n";
}
my $linenum = $inputCounter - 1;
print STDERR $headerObject->fullpath().":$linenum: warning: Unknown class type '$classType' (known: cpp, objC, intf, occCat)\n";
}
}
} print STDERR "Top Level Point 1000\n" if ($tlhangDebug);
$headerObject->reparentModuleMembers();
my @newobjs = ();
foreach my $class (@perHeaderClassObjects) {
if (!$class->isModule()) {
push(@newobjs, $class);
}
}
@perHeaderClassObjects = @newobjs;
if ($retainheader) {
push (@headerObjects, $headerObject);
}
}
print STDERR "Top Level Point 1100\n" if ($tlhangDebug);
my ($headercpphashref, $headercpparghashref) = getAndClearCPPHash();
my %headercpphash = %{$headercpphashref};
my %headercpparghash = %{$headercpparghashref};
my $includeListRef = $HeaderDoc::perHeaderIncludes{$fullpath};
if ($includeListRef) {
my @includeList = @{$includeListRef};
print STDERR "LISTING PER HEADER INCLUDES\n" if ($includeDebug);
foreach my $include (@includeList) {
print STDERR "INCLUDE: $include\n" if ($includeDebug);
my $pathname = $include;
$pathname =~ s/^\s*//s;
$pathname =~ s/\s*$//s;
if ($pathname !~ s/^\<(.*)\>$/$1/s) {
$pathname =~ s/^\"(.*)\"$/$1/s;
}
print STDERR "SANITIZED PATHNAME: $pathname\n" if ($includeDebug);
my $includedfilename = basename($pathname);
print STDERR "INCLUDED FILENAME: $includedfilename\n" if ($includeDebug);
if ($HeaderDoc::HeaderFileCPPHashHash{$includedfilename}) {
print STDERR "FOUND. MERGING HASHES\n" if ($includeDebug);
%headercpphash = (%headercpphash, %{$HeaderDoc::HeaderFileCPPHashHash{$includedfilename}});
%headercpparghash = (%headercpparghash, %{$HeaderDoc::HeaderFileCPPArgHashHash{$includedfilename}});
printCPPHashes(\%headercpphash, \%headercpparghash) if ($includeDebug)
}
print STDERR "\n" if ($includeDebug);
}
} else {
print STDERR "NO PER HEADER INCLUDES (NO REF)\n" if ($includeDebug);
}
print STDERR "Top Level Point 1200\n" if ($tlhangDebug);
$HeaderDoc::HeaderFileCPPHashHash{$basefilename} = \%headercpphash;
$HeaderDoc::HeaderFileCPPArgHashHash{$basefilename} = \%headercpparghash;
foreach my $class (@perHeaderClassObjects) {
if ($headerIncluded{$basefilename}) {
push(@classObjects, $class);
}
}
if (@perHeaderClassObjects && !$xml_output) {
foreach my $class (@perHeaderClassObjects) {
mergeClass($class);
}
}
print STDERR "Top Level Point 1300\n" if ($tlhangDebug);
if (!$skip_header_processing) {
if (@perHeaderCategoryObjects && !$xml_output) {
foreach my $obj (@perHeaderCategoryObjects) {
my $nameOfAssociatedClass = $obj->className();
my $categoryName = $obj->categoryName();
my $localDebug = 0;
if (exists $objCClassNameToObject{$nameOfAssociatedClass}) {
my $associatedClass = $objCClassNameToObject{$nameOfAssociatedClass};
print STDERR "AC: $associatedClass\n" if ($localDebug);
print STDERR "OBJ: $obj\n" if ($localDebug);
my $methods = $obj->methods();
$associatedClass->addToMethods($obj->methods());
my $owner = $obj->headerObject();
print STDERR "Found category with name $categoryName and associated class $nameOfAssociatedClass\n" if ($localDebug);
print STDERR "Associated class exists\n" if ($localDebug);
print STDERR "Added methods to associated class\n" if ($localDebug);
if (ref($owner)) {
my $numCatsBefore = $owner->categories();
$owner->removeFromCategories($obj);
my $numCatsAfter = $owner->categories();
print STDERR "Number of categories before: $numCatsBefore after:$numCatsAfter\n" if ($localDebug);
} else {
my $fullpath = $HeaderDoc::headerObject->fullpath();
my $linenum = $obj->linenum();
print STDERR "$fullpath:$linenum: warning: Couldn't find Header object that owns the category with name $categoryName.\n";
}
my $assocapio = $associatedClass->APIOwner();
$assocapio->resetAppleRefUsed();
if ($man_output) {
$assocapio->writeHeaderElementsToManPage();
} elsif ($function_list_output) {
$assocapio->writeFunctionListToStdOut();
} elsif ($xml_output) {
$assocapio->writeHeaderElementsToXMLPage();
} else {
$assocapio->fixupTypeRequests();
$assocapio->setupAPIReferences();
$assocapio->createFramesetFile();
$assocapio->createTOCFile();
$assocapio->writeHeaderElements();
$assocapio->writeHeaderElementsToCompositePage();
$assocapio->createContentFile() if (!$HeaderDoc::ClassAsComposite);
}
if ($doxytag_output) {
$assocapio->writeHeaderElementsToDoxyFile();
}
} else {
print STDERR "Found category with name $categoryName and associated class $nameOfAssociatedClass\n" if ($localDebug);
print STDERR "Associated class doesn't exist\n" if ($localDebug);
}
}
}
print STDERR "Top Level Point 1400\n" if ($tlhangDebug);
if ($doxytag_output) {
$headerObject->writeHeaderElementsToDoxyFile();
}
if ($man_output) {
$headerObject->writeHeaderElementsToManPage();
} elsif ($function_list_output) {
$headerObject->writeFunctionListToStdOut();
} elsif ($xml_output) {
$headerObject->writeHeaderElementsToXMLPage();
} else {
$headerObject->fixupTypeRequests();
$headerObject->setupAPIReferences();
$headerObject->createFramesetFile();
$headerObject->createTOCFile();
$headerObject->writeHeaderElements();
$headerObject->writeHeaderElementsToCompositePage();
$headerObject->createContentFile() if (!$HeaderDoc::ClassAsComposite);
}
} print STDERR "Top Level Point 1500\n" if ($tlhangDebug);
foreach my $class (@perHeaderClassObjects) {
if (!$headerIncluded{$basefilename}) {
$class->free($retainheader ? 2 : 0);
}
}
if (!$retainheader) {
$headerObject->free($headerIncluded{$basefilename});
$HeaderDoc::headerObject = undef;
$HeaderDoc::currentClass = undef;
}
print "Object $headerObject should go away.\n" if ($HeaderDoc::debugAllocations);
$headerObject = undef;
print "Object should be gone.\n" if ($HeaderDoc::debugAllocations);
print STDERR "Top Level Point 1600\n" if ($tlhangDebug);
}
if ($doxytag_output && $specifiedOutputDir) {
mergeDoxyTags($specifiedOutputDir);
}
dumpCaches() if ($HeaderDoc::debugAllocations);
if ($quietLevel eq "0") {
print STDERR "...done\n";
}
if ($HeaderDoc::exitstatus != 0) {
print STDERR "WARNING: One or more input files could not be read. Be sure to check the\n";
print STDERR "output to make sure that all desired content was documented.\n";
}
exit $HeaderDoc::exitstatus;
sub mergeClass
{
my $class = shift;
my $superName = $class->checkShortLongAttributes("Superclass");
my $merge_content = 1;
my $localDebug = 0;
if ($class->isMerged()) { return; }
if (!$class->explicitSuper() && !$HeaderDoc::IncludeSuper) {
$merge_content = 0;
}
if ($superName) {
if (!($superName eq $class->name())) {
my $super = 0;
foreach my $mergeclass (@classObjects) {
if ($mergeclass->name eq $superName) {
$super = $mergeclass;
}
}
if ($super) {
if (!$super->isMerged()) {
mergeClass($super);
}
my @methods = $super->methods();
my @functions = $super->functions();
my @vars = $super->vars();
my @structs = $super->structs();
my @enums = $super->enums();
my @pdefines = $super->pDefines();
my @typedefs = $super->typedefs();
my @constants = $super->constants();
my @classes = $super->classes();
my $name = $super->name();
my $discussion = $super->discussion();
$class->inheritDoc($discussion);
if ($merge_content) {
my @childfunctions = $class->functions();
my @childmethods = $class->methods();
my @childvars = $class->vars();
my @childstructs = $class->structs();
my @childenums = $class->enums();
my @childpdefines = $class->pDefines();
my @childtypedefs = $class->typedefs();
my @childconstants = $class->constants();
my @childclasses = $class->classes();
if (@methods) {
foreach my $method (@methods) {
if ($method->accessControl() eq "private") {
next;
}
my $include = 1;
foreach my $childmethod (@childmethods) {
if ($method->name() eq $childmethod->name()) {
if ($method->parsedParamCompare($childmethod)) {
$include = 0; last;
}
}
}
if (!$include) { next; }
my $newobj = $method->clone();
$class->addToMethods($method);
$newobj->apiOwner($class);
if ($newobj->origClass() eq "") {
$newobj->origClass($name);
}
$HeaderDoc::ignore_apiuid_errors = 1;
my $junk = $newobj->apirefSetup(1);
$HeaderDoc::ignore_apiuid_errors = 0;
}
}
if (@functions) {
foreach my $function (@functions) {
if ($function->accessControl() eq "private") {
next;
}
my $include = 1;
foreach my $childfunction (@childfunctions) {
if ($function->name() eq $childfunction->name()) {
if ($function->parsedParamCompare($childfunction)) {
$include = 0; last;
}
}
}
if (!$include) { next; }
my $newobj = $function->clone();
$class->addToFunctions($newobj);
$newobj->apiOwner($class);
if ($newobj->origClass() eq "") {
$newobj->origClass($name);
}
$HeaderDoc::ignore_apiuid_errors = 1;
my $junk = $newobj->apirefSetup(1);
$HeaderDoc::ignore_apiuid_errors = 0;
}
}
if (@vars) {
foreach my $var (@vars) {
if ($var->accessControl() eq "private") {
next;
}
my $include = 1;
foreach my $childvar (@childvars) {
if ($var->name() eq $childvar->name()) {
$include = 0; last;
}
}
if (!$include) { next; }
my $newobj = $var->clone();
$class->addToVars($newobj);
$newobj->apiOwner($class);
if ($newobj->origClass() eq "") {
$newobj->origClass($name);
}
$HeaderDoc::ignore_apiuid_errors = 1;
my $junk = $newobj->apirefSetup(1);
$HeaderDoc::ignore_apiuid_errors = 0;
}
}
if (@structs) {
foreach my $struct (@structs) {
if ($struct->accessControl() eq "private") {
next;
}
my $include = 1;
foreach my $childstruct (@childstructs) {
if ($struct->name() eq $childstruct->name()) {
$include = 0; last;
}
}
my $newobj = $struct->clone();
$class->addToStructs($newobj);
$newobj->apiOwner($class);
if ($newobj->origClass() eq "") {
$newobj->origClass($name);
}
$HeaderDoc::ignore_apiuid_errors = 1;
my $junk = $newobj->apirefSetup(1);
$HeaderDoc::ignore_apiuid_errors = 0;
}
}
if (@enums) {
foreach my $enum (@enums) {
if ($enum->accessControl() eq "private") {
next;
}
my $include = 1;
foreach my $childenum (@childenums) {
if ($enum->name() eq $childenum->name()) {
$include = 0; last;
}
}
my $newobj = $enum->clone();
$class->addToEnums($newobj);
$newobj->apiOwner($class);
if ($newobj->origClass() eq "") {
$newobj->origClass($name);
}
$HeaderDoc::ignore_apiuid_errors = 1;
my $junk = $newobj->apirefSetup(1);
$HeaderDoc::ignore_apiuid_errors = 0;
}
}
if (@pdefines) {
foreach my $pdefine (@pdefines) {
if ($pdefine->accessControl() eq "private") {
next;
}
my $include = 1;
foreach my $childpdefine (@childpdefines) {
if ($pdefine->name() eq $childpdefine->name()) {
$include = 0; last;
}
}
my $newobj = $pdefine->clone();
$class->addToPDefines($newobj);
$newobj->apiOwner($class);
if ($newobj->origClass() eq "") {
$newobj->origClass($name);
}
$HeaderDoc::ignore_apiuid_errors = 1;
my $junk = $newobj->apirefSetup(1);
$HeaderDoc::ignore_apiuid_errors = 0;
}
}
if (@typedefs) {
foreach my $typedef (@typedefs) {
if ($typedef->accessControl() eq "private") {
next;
}
my $include = 1;
foreach my $childtypedef (@childtypedefs) {
if ($typedef->name() eq $childtypedef->name()) {
$include = 0; last;
}
}
my $newobj = $typedef->clone();
$class->addToTypedefs($newobj);
$newobj->apiOwner($class);
if ($newobj->origClass() eq "") {
$newobj->origClass($name);
}
$HeaderDoc::ignore_apiuid_errors = 1;
my $junk = $newobj->apirefSetup(1);
$HeaderDoc::ignore_apiuid_errors = 0;
}
}
if (@constants) {
foreach my $constant (@constants) {
if ($constant->accessControl() eq "private") {
next;
}
my $include = 1;
foreach my $childconstant (@childconstants) {
if ($constant->name() eq $childconstant->name()) {
$include = 0; last;
}
}
my $newobj = $constant->clone();
$class->addToConstants($newobj);
$newobj->apiOwner($class);
if ($newobj->origClass() eq "") {
$newobj->origClass($name);
}
$HeaderDoc::ignore_apiuid_errors = 1;
my $junk = $newobj->apirefSetup(1);
$HeaderDoc::ignore_apiuid_errors = 0;
}
}
if (@classes) {
foreach my $classref (@classes) {
my $class = %{$class};
bless($class, "HeaderDoc::APIOwner");
bless($class, $class->class());
if ($class->accessControl() eq "private") {
next;
}
my $include = 1;
foreach my $childclassref (@childclasses) {
my $childclass = %{$childclassref};
bless($class, "HeaderDoc::APIOwner");
bless($class, $class->class());
if ($class->name() eq $childclass->name()) {
$include = 0; last;
}
}
my $newobj = $class->clone();
$class->addToClasses($newobj);
$newobj->apiOwner($class);
if ($newobj->origClass() eq "") {
$newobj->origClass($name);
}
$HeaderDoc::ignore_apiuid_errors = 1;
my $junk = $newobj->apirefSetup(1);
$HeaderDoc::ignore_apiuid_errors = 0;
}
}
} }
}
}
my $ai = $class->alsoInclude();
if ($ai) {
my @aiarray = @{$ai};
foreach my $entry (@aiarray) {
my $explicit = 0;
my $uid = "";
$entry =~ s/^\s*//s;
$entry =~ s/\s*$//s;
if ($entry =~ /^\/\//) {
$uid = $entry;
$explicit = 1;
} else {
$uid = resolveLink($class, $entry, "included")
}
print STDERR "UID IS \"$uid\"\n" if ($localDebug);
my $obj = objectForUID($uid);
if (!$obj) {
warn "Object for \"$uid\" could not be found.\n";
if (!$explicit) {
warn " This should not happen. Please file a bug.\n";
}
} else {
my $objcl = ref($obj) || $obj;
print STDERR "OBJ IS $obj\n" if ($localDebug);
if ($objcl =~ /HeaderDoc::Function/) {
$class->addToFunctions($obj);
$obj->apiOwner()->removeFromFunctions($obj);
} elsif ($objcl =~ /HeaderDoc::PDefine/) {
$class->addToPDefines($obj);
$obj->apiOwner()->removeFromPDefines($obj);
} else {
warn "Don't know how to add object of type $objcl to pseudoclass\n";
}
}
}
}
$class->isMerged(1);
}
sub mergeDoxyTags
{
my $outputDir = shift;
find(\&getDoxyTagFiles, $outputDir);
my $tagfileoutput = "";
my $temp = $/;
$/ = undef;
foreach my $file (@doxyTagFiles) {
open(MYFILE, "<$file");
my $temp = <MYFILE>;
$temp =~ s/^\s*<tagfile>\n*//s;
$temp =~ s/\n\s*<\/tagfile>.*$//s;
$tagfileoutput .= "\n".$temp;
close(MYFILE);
if (!$debugging) {
unlink($file);
}
}
$/ = $temp;
$tagfileoutput =~ s/^\n//;
my $tagfile = "$outputDir".$pathSeparator."doxytags.xml";
open(MYFILE, ">$tagfile");
print MYFILE "<tagfile>\n";
print MYFILE $tagfileoutput;
print MYFILE "\n</tagfile>\n";
close(MYFILE);
}
sub mkdir_recursive
{
my $path = shift;
my $mask = shift;
my @pathparts = split (/$pathSeparator/, $path);
my $curpath = "";
my $first = 1;
foreach my $pathpart (@pathparts) {
if ($first) {
$first = 0;
$curpath = $pathpart;
} elsif (! -e "$curpath$pathSeparator$pathpart") {
if (!mkdir("$curpath$pathSeparator$pathpart", 0777)) {
return 0;
}
$curpath .= "$pathSeparator$pathpart";
} else {
$curpath .= "$pathSeparator$pathpart";
}
}
return 1;
}
sub strip
{
my $filename = shift;
my $short_output_path = shift;
my $long_output_path = shift;
my $input_path_and_filename = shift;
my $inputRef = shift;
my @inputLines = @$inputRef;
my $localDebug = 0;
my $output_file = "$short_output_path$pathSeparator$input_path_and_filename";
my $output_path = "$short_output_path";
my @pathparts = split(/($pathSeparator)/, $input_path_and_filename);
my $junk = pop(@pathparts);
my $input_path = "";
foreach my $part (@pathparts) {
$input_path .= $part;
}
if ($localDebug) {
print STDERR "output path: $output_path\n";
print STDERR "short output path: $short_output_path\n";
print STDERR "long output path: $long_output_path\n";
print STDERR "input path and filename: $input_path_and_filename\n";
print STDERR "input path: $input_path\n";
print STDERR "filename: $filename\n";
print STDERR "output file: $output_file\n";
}
if (-e $output_file) {
$output_file .= "-stripped";
print STDERR "WARNING: output file exists. Saving as\n\n";
print STDERR " $output_file\n\n";
print STDERR "instead.\n";
}
if (! -e "$output_path$pathSeparator$input_path") {
unless (mkdir_recursive ("$output_path$pathSeparator$input_path", 0777)) {
die "Error: $output_path$pathSeparator$input_path does not exist. Exiting. \n$!\n";
}
}
open(OUTFILE, ">$output_file") || die "Can't write $output_file.\n";
if ($^O =~ /MacOS/io) {MacPerl::SetFileInfo('R*ch', 'TEXT', "$output_file");};
my $inComment = 0;
my $text = "";
my $localDebug = 0;
foreach my $line (@inputLines) {
print STDERR "line $line\n" if ($localDebug);
print STDERR "inComment $inComment\n" if ($localDebug);
if (($line =~ /^\/\*\!/o) || (($lang eq "java" || $HeaderDoc::parse_javadoc) && ($line =~ /^\s*\/\*\*[^*]/o))) { $inComment = 1;
}
if ($inComment && ($line =~ /\*\//o)) {
$inComment = 2;
}
if (!$inComment) { $text .= $line; }
if ($inComment == 2) {
$inComment = 0;
}
}
print OUTFILE $text;
close OUTFILE;
}
sub processIncludes($$$)
{
my $lineArrayRef = shift;
my $pathname = shift;
my $lang = shift;
my $sublang = shift;
my @lines = @{$lineArrayRef};
my $filename = basename($pathname);
my $ah = HeaderDoc::AvailHelper->new();
my @includeList = ();
my $availDebug = 0;
my @ranges = ();
my @rangestack = ();
my $linenum = 1;
my $continuation = 0;
my $contline = "";
my $inComment = 0;
my $parseTokensRef = parseTokens($lang, $sublang);
foreach my $line (@lines) {
$inComment = prefilterCommentCheck($line, $parseTokensRef, $inComment);
if ($continuation) {
if ($line =~ /\\\s*$/) {
$contline .= $line;
} else {
my $rangeref = pop(@rangestack);
my $range = ${$rangeref};
$contline .= $line;
$continuation = 0;
if ($HeaderDoc::auto_availability) {
$range->text($ah->parseString($contline, $pathname, $linenum));
}
push(@rangestack, \$range);
}
} else {
my $hackline = $line;
if ($hackline =~ s/^\s* my $incfile = "";
if ($hackline =~ /^(<.*?>)/o) {
$incfile = $1;
} elsif ($hackline =~ /^(\".*?\")/o) {
$incfile = $1;
} else {
warn "$pathname:$linenum: warning: Unable to determine include file name for \"$line\".\n";
}
if (length($incfile)) {
push(@includeList, $incfile);
}
}
if ($hackline =~ s/^\s* print STDERR "STARTRANGE ifdef: $hackline\n" if ($availDebug);
my $range = HeaderDoc::LineRange->new();
$range->start($linenum);
push(@rangestack, \$range);
}
if ($hackline =~ s/^\s* print STDERR "STARTRANGE ifndef: $hackline\n" if ($availDebug);
my $range = HeaderDoc::LineRange->new();
$range->start($linenum);
$range->text("");
push(@rangestack, \$range);
}
if ($hackline =~ s/^\s* print STDERR "STARTRANGE if: $hackline\n" if ($availDebug);
my $range = HeaderDoc::LineRange->new();
$range->start($linenum);
if ($hackline =~ /\\\s*$/) {
$continuation = 1;
} else {
if ($HeaderDoc::auto_availability) {
$range->text($ah->parseString($hackline, $pathname, $linenum));
}
}
push(@rangestack, \$range);
}
if ($hackline =~ s/^\s* print STDERR "ENDRANGE: $hackline\n" if ($availDebug);
my $rangeref = pop(@rangestack);
if ($rangeref) {
my $range = ${$rangeref};
bless($range, "HeaderDoc::LineRange");
$range->end($linenum);
if (length($range->text())) { push(@ranges, \$range); }
} else {
warn "$pathname:$linenum: warning: Unbalanced #endif found in prescan.\n";
}
}
$linenum++;
}
}
if (0) {
print STDERR "Includes for \"$filename\":\n";
foreach my $name (@includeList) {
print STDERR "$name\n";
}
}
if ($availDebug) {
print STDERR "Ranges for \"$filename\":\n";
foreach my $rangeref (@ranges) {
my $range = ${$rangeref};
bless($range, "HeaderDoc::LineRange");
print STDERR "-----\n";
print STDERR "START: ".$range->start()."\n";
print STDERR "END: ".$range->end()."\n";
print STDERR "TEXT: ".$range->text()."\n";
}
}
$HeaderDoc::perHeaderIncludes{$pathname} = \@includeList;
$HeaderDoc::perHeaderRanges{$pathname} = \@ranges;
}
sub prefilterCommentCheck
{
my $line = shift;
my $parseTokensRef = shift;
my $inComment = shift;
my $localDebug = 0;
my %parseTokens = %{$parseTokensRef};
my $soc = $parseTokens{soc};
my $eoc = $parseTokens{eoc};
my $ilc = $parseTokens{ilc};
my $ilc_b = $parseTokens{ilc_b};
my @parts = ();
if ($soc && $ilc && $ilc_b) {
@parts = split(/(\Q$soc\E|\Q$eoc\E|\Q$ilc\E|\Q$ilc_b\E|[\r\n])/, $line);
} elsif ($soc && $ilc) {
@parts = split(/(\Q$soc\E|\Q$eoc\E|\Q$ilc\E|[\r\n])/, $line);
} elsif ($ilc && $ilc_b) {
@parts = split(/(\Q$ilc\E|\Q$ilc_b\E|[\r\n])/, $line);
} elsif ($ilc) {
@parts = split(/(\Q$ilc\E|[\r\n])/, $line);
} else {
return 0;
}
if ($inComment == 2) { $inComment = 0; }
foreach my $part (@parts) {
print STDERR "checking $part (SOC: $soc ILC: $ilc ILC_B: $ilc_b EOC: $eoc)\n" if ($localDebug);
if (($eoc) && ($part eq $eoc) && ($inComment == 1)) {
$inComment = 0;
print STDERR "GOT EOC\n" if ($localDebug);
} elsif (($part =~ /[\r\n]/) && ($inComment == 2)) {
print STDERR "GOT NEWLINE IN ILC\n" if ($localDebug);
$inComment = 0;
} elsif (!$inComment) {
if (($soc) && ($part eq $soc)) {
print STDERR "GOT SOC\n" if ($localDebug);
$inComment = 1;
} elsif (($ilc) && ($part eq $ilc)) {
print STDERR "GOT ILC\n" if ($localDebug);
$inComment = 2;
} elsif (($ilc_b) && ($part eq $ilc_b)) {
print STDERR "GOT ILC_B\n" if ($localDebug);
$inComment = 2;
}
}
}
return $inComment;
}
my %pathForInclude;
sub fix_dependency_order
{
my $inputlistref = shift;
my @inputfiles = @{$inputlistref};
my $treetop = undef;
my $localDebug = 0;
%pathForInclude = ();
print STDERR "Scanning dependencies.\n" if ($localDebug || $debugging);
my $foundcount = 0;
foreach my $rawfilename (@inputfiles) {
my $filename = basename($rawfilename);
my $fullpath=getAbsPath($rawfilename);
$pathForInclude{$filename} = $rawfilename;
print STDERR "IN FILE: $filename:\n" if ($localDebug);
my $curnoderef = HeaderDoc::Dependency->findname($filename);
my $curnode = undef;
my $force = 0;
if ($curnoderef) {
print STDERR "Node exists\n" if ($localDebug);
$curnode = ${$curnoderef};
bless($curnode, "HeaderDoc::Dependency");
if ($curnode->{EXISTS}) {
print STDERR "Node marked with EXISTS. Setting force -> 1\n" if ($localDebug);
warn "WARNING: Multiple files named \"$filename\" found in argument\n".
"list. Dependencies may not work as expected.\n";
$force = 1;
}
}
if (!$curnoderef || $force) {
print STDERR "CNR: $curnoderef FORCE: $force\n" if ($localDebug);
$curnode = HeaderDoc::Dependency->new();
if (!$treetop) {
$treetop = $curnode;
$curnode = HeaderDoc::Dependency->new();
}
$curnode->name($rawfilename);
$curnode->depname($filename);
$curnode->{EXISTS} = 1;
} else {
print STDERR "CNR: $curnoderef\n" if ($localDebug);
$curnode = ${$curnoderef};
bless($curnode, "HeaderDoc::Dependency");
print STDERR " CN: $curnode\n" if ($localDebug);
$curnode->name($rawfilename);
$curnode->{EXISTS} = 1;
$foundcount ++;
}
foreach my $include (@{$HeaderDoc::perHeaderIncludes{$fullpath}}) {
print STDERR " COMPARE INCLUDE: $include\n" if ($localDebug);
my $tempname = $include;
$tempname =~ s/^\s*//s;
$tempname =~ s/\s*$//s;
if ($tempname !~ s/^\<(.*)\>$/$1/s) {
$tempname =~ s/^\"(.*)\"$/$1/s;
}
my $rawincname = $tempname;
$tempname = basename($tempname);
print STDERR " TMPNM: $tempname\n" if ($localDebug);
my $noderef = HeaderDoc::Dependency->findname($tempname);
my $node = undef;
if (!$noderef) {
print STDERR "No existing reference found.\n" if ($localDebug);
$node = HeaderDoc::Dependency->new();
$node->name($rawincname);
$node->depname($tempname);
} else {
print STDERR "Existing reference found.\n" if ($localDebug);
$node = HeaderDoc::Dependency->new();
$node = ${$noderef};
bless($node, "HeaderDoc::Dependency");
}
$curnode->addchild($node);
}
$treetop->addchild($curnode);
}
print STDERR "foundcount: $foundcount\n" if ($localDebug);
print STDERR "doing depth-first traversal.\n" if ($localDebug || $debugging);
my $ret = depthfirst($treetop);
if ($localDebug) {
foreach my $entry (@{$ret}) {
print STDERR "$entry ";
}
}
$treetop = undef;
print STDERR "\ndone.\n" if ($localDebug || $debugging);
return $ret;
}
my @deplevels = ();
sub set_node_depths
{
my $node = shift;
my $depth = shift;
my $localDebug = 0;
if ($depth <= 1) { print STDERR "Generating depth for ".$node->{NAME}."\n" if ($localDebug); }
if ($node->{MARKED}) {
return;
}
$node->{MARKED} = 1;
if ($node->{DEPTH} <= $depth || !$node->{DEPTH}) {
$node->{DEPTH} = $depth;
} else {
$node->{MARKED} = 0;
return;
}
foreach my $childref (@{$node->{CHILDREN}}) {
my $child = ${$childref};
bless($child, "HeaderDoc::Dependency");
set_node_depths($child, $depth + 1);
}
$node->{MARKED} = 0;
}
my $maxdependencydepth = 0;
sub generate_depth_levels
{
my $node = shift;
my $depth = shift;
my $localDebug = 0;
if ($node->{MARKED}) {
return;
}
$node->{MARKED} = 1;
print STDERR "NODE DEPTH: ".$node->{DEPTH}."\n" if ($localDebug);;
my @levelarr = ();
if ($deplevels[$node->{DEPTH}]) {
@levelarr = @{$deplevels[$node->{DEPTH}]};
}
push(@levelarr, \$node);
$deplevels[$node->{DEPTH}] = \@levelarr;
if ($node->{DEPTH} > $maxdependencydepth) {
print STDERR "MAX DEPTH: $maxdependencydepth -> " if ($localDebug);
$maxdependencydepth = $node->{DEPTH};
print STDERR "$maxdependencydepth\n" if ($localDebug);
}
foreach my $childref (@{$node->{CHILDREN}}) {
my $child = ${$childref};
bless($child, "HeaderDoc::Dependency");
generate_depth_levels($child, $depth + 1);
}
}
sub depthfirst
{
my @rawfiles = ();
my $treetop = shift;
print STDERR "Doing recursive sort by depth\n" if ($debugging);
set_node_depths($treetop, 0);
print STDERR "Generating depth levels\n" if ($debugging);
generate_depth_levels($treetop);
my $depth = $maxdependencydepth;
$treetop->dbprint() if ($debugging);
print STDERR "Sweeping levels from depth $maxdependencydepth:\n" if ($debugging);
my $level = $depth;
while ($level >= 0) {
print STDERR "Level $level\n" if ($debugging);
my @array = ();
if ($deplevels[$level]) {
@array = @{$deplevels[$level]};
} else {
print STDERR "No entries at level $level. How peculiar.\n" if ($debugging);
}
foreach my $dep (@array) {
$dep = ${$dep};
bless($dep, "HeaderDoc::Dependency");
print STDERR "Adding ".$dep->name()."\n" if ($debugging);
if ($dep->{EXISTS}) {
push(@rawfiles, $dep->name());
}
}
$level--;
}
print STDERR "done sweeping.\n" if ($debugging);
my @files = ();
my %namehash = ();
my $filename;
foreach $filename (@inputFiles) {
print STDERR "File: $filename\n" if ($debugging);
$namehash{$filename} = 1;
}
foreach my $filename (@rawfiles) {
if (length($filename)) {
if ($namehash{$filename}) {
print STDERR "pushing $filename\n" if ($debugging);
push(@files, $filename);
$namehash{$filename} = 0; } else {
print STDERR "skipping $filename\n" if ($debugging);
}
}
}
return \@files;
}
my %pathparts = ();
sub depthfirst_rec
{
my $noderef = shift;
my $level = shift;
my $maxlevel = $level;
my $norecurse = 0;
if (!$noderef) { return; }
my $node = ${$noderef};
bless($node, "HeaderDoc::Dependency");
if ($node->{MARKED}) {
$norecurse = 1;
}
if ($pathparts{$node->depname()}) {
return;
}
if ($node->{MARKED} < $level+1) {
$node->{MARKED} = $level + 1;
}
if (!$norecurse && $node->{CHILDREN}) {
my $opp = $pathparts{$node->depname()};
if ($opp == undef) { $opp = 0; }
$pathparts{$node->depname()} = 1;
foreach my $child (@{$node->{CHILDREN}}) {
my $templevel = depthfirst_rec($child, $level + 1);
if ($templevel > $maxlevel) { $maxlevel = $templevel; }
}
$pathparts{$node->depname()} = $opp;
}
my @oldarr = ();
if ($deplevels[$level]) {
@oldarr = @{$deplevels[$level]};
}
push(@oldarr, \$node);
$deplevels[$level] = \@oldarr;
return $maxlevel;
}
sub printVersionInfo {
my $bp = $HeaderDoc::BlockParse::VERSION;
my $av = $HeaderDoc::APIOwner::VERSION;
my $hev = $HeaderDoc::HeaderElement::VERSION;
my $hv = $HeaderDoc::Header::VERSION;
my $cppv = $HeaderDoc::CPPClass::VERSION;
my $objcclassv = $HeaderDoc::ObjCClass::VERSION;
my $objccnv = $HeaderDoc::ObjCContainer::VERSION;
my $objccatv = $HeaderDoc::ObjCCategory::VERSION;
my $objcprotocolv = $HeaderDoc::ObjCProtocol::VERSION;
my $fv = $HeaderDoc::Function::VERSION;
my $mv = $HeaderDoc::Method::VERSION;
my $depv = $HeaderDoc::Dependency::VERSION;
my $lr = $HeaderDoc::LineRange::VERSION;
my $ah = $HeaderDoc::AvailHelper::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;
my $pd = $HeaderDoc::PDefine::VERSION;
my $pt = $HeaderDoc::ParseTree::VERSION;
my $ps = $HeaderDoc::ParserState::VERSION;
my $ih = $HeaderDoc::IncludeHash::VERSION;
my $rg = $HeaderDoc::Regen::VERSION;
print STDERR "---------------------------------------------------------------------\n";
print STDERR "\tHeaderDoc Version: ".$HeaderDoc_Version."\n\n";
print STDERR "\theaderDoc2HTML - $VERSION\n";
print STDERR "\tModules:\n";
print STDERR "\t\tAPIOwner - $av\n";
print STDERR "\t\tAvailHelper - $ah\n";
print STDERR "\t\tBlockParse - $bp\n";
print STDERR "\t\tCPPClass - $cppv\n";
print STDERR "\t\tConstant - $cv\n";
print STDERR "\t\tDependency - $depv\n";
print STDERR "\t\tEnum - $ev\n";
print STDERR "\t\tFunction - $fv\n";
print STDERR "\t\tHeader - $hv\n";
print STDERR "\t\tHeaderElement - $hev\n";
print STDERR "\t\tIncludeHash - $ih\n";
print STDERR "\t\tLineRange - $lr\n";
print STDERR "\t\tMethod - $mv\n";
print STDERR "\t\tMinorAPIElement - $me\n";
print STDERR "\t\tObjCCategory - $objccatv\n";
print STDERR "\t\tObjCClass - $objcclassv\n";
print STDERR "\t\tObjCContainer - $objccnv\n";
print STDERR "\t\tObjCProtocol - $objcprotocolv\n";
print STDERR "\t\tPDefine - $pd\n";
print STDERR "\t\tParseTree - $pt\n";
print STDERR "\t\tParserState - $ps\n";
print STDERR "\t\tStruct - $sv\n";
print STDERR "\t\tTypedef - $tv\n";
print STDERR "\t\tUtilities - $uv\n";
print STDERR "\t\tVar - $vv\n";
print STDERR "---------------------------------------------------------------------\n";
}
sub SDump
{
my $arg = shift;
my $text = shift;
print STDERR "At position $text:\n";
Dump($arg);
print STDERR "End dump\n";
}
sub newtest
{
$/ = "\n";
print STDERR "Enter name of test\n";
my $name = <STDIN>;
$name =~ s/\n$//s;
my $lang = "";
my $sublang = "";
while ($lang !~ /^(C|java|javascript|pascal|php|perl|Csource|shell|csh|IDL|MIG|ruby|python|applescript|tcl)$/) {
print STDERR "Enter language (C|java|javascript|pascal|php|perl|Csource|shell|csh|IDL|MIG|ruby|python|applescript|tcl)\n";
$lang = <STDIN>;
$lang =~ s/\n$//s;
if ($lang eq "IDL") {
$lang = "C";
$sublang = "IDL";
} elsif ($lang eq "MIG") {
$lang = "C";
$sublang = "MIG";
} elsif ($lang eq "csh") {
$lang = "shell";
$sublang = "csh";
} elsif ($lang eq "javascript") {
$lang = "java";
$sublang = "javascript";
} else {
$sublang = $lang;
}
}
$HeaderDoc::lang = $lang;
$HeaderDoc::sublang = $sublang;
my $type = "";
if ($lang eq "C" || $lang eq "Csource") {
while ($type !~ /(parser|cpp)/) {
print STDERR "Enter type of test (parser|cpp)\n";
$type = <STDIN>;
$type =~ s/\n$//s;
}
} else {
$type = "parser";
}
$/ = undef;
my $cppcode = "";
my $comment = "";
if ($type eq "parser") {
print STDERR "Paste in HeaderDoc comment block.\nPress control-d on a new line when done.\n";
$comment = <STDIN>;
seek(STDIN,0,0);
print STDERR "Paste in block of code.\nPress control-d on a new line when done.\n";
} else {
print STDERR "Paste in initial macros.\nPress control-d on a new line when done.\n";
$cppcode = <STDIN>;
seek(STDIN,0,0);
print STDERR "Paste in block of code to permute with this macro.\nPress control-d on a new line when done.\n";
}
my $code = <STDIN>;
seek(STDIN,0,0);
print STDERR "Optionally paste or type in a message to be displayed if the test fails.\nPress control-d on a new line when done.\n";
my $failmsg = <STDIN>;
seek(STDIN,0,0);
my $test = HeaderDoc::Test->new( "NAME" => $name, "COMMENT" => $comment, "CODE" => $code, "LANG" => $lang, "SUBLANG" => $sublang, "TYPE" => $type, "CPPCODE" => $cppcode, "FAILMSG" => $failmsg );
$test->runTest();
$test->{EXPECTED_RESULT} = $test->{RESULT};
$test->{EXPECTED_RESULT_ALLDECS} = $test->{RESULT_ALLDECS};
my $filename = $test->{FILENAME};
my $testdir = $HeaderDoc::testdir;
if (-d "$testdir") {
if ($type eq "parser") {
$filename = "$testdir/parser_tests/$filename";
} else {
$filename = "$testdir/c_preprocessor_tests/$filename";
}
} else {
$filename = "/tmp/$filename.test";
}
if (-f $filename) {
print "You are about to overwrite an existing test case. Continue? (yes|no)\n";
$/ = "\n";
my $reply = <STDIN>;
$reply =~ s/\n$//s;
if ($reply ne "yes") {
print "Cancelled.\n";
exit(-1);
}
}
$test->writeToFile($filename);
$test->writeToPlist($filename);
print "Wrote test data to \"$filename\"\n";
$test->dbprint();
}
sub runtests
{
my $mode = shift;
my $argref = shift;
my @args = @{$argref};
my $ok_count = 0;
my $fail_count = 0;
my @testlist = undef;
my $update = 0;
if ($mode eq "update") {
$update = 1;
}
my $force = 0;
if ($mode eq "forceupdate") {
$update = 1;
$force = 1;
}
my $testdir = $HeaderDoc::testdir;
my ($encoding, $linesref) = linesFromFile($testdir.$pathSeparator."version", 0);
my $installedversion = "";
if ($linesref) {
my @lines = @{$linesref};
$installedversion = $lines[0];
}
$installedversion =~ s/^\s*//sg;
$installedversion =~ s/\s*$//sg;
if (!$HeaderDoc::local_tests) {
if ($installedversion ne $HeaderDoc::testsuite_version) {
print STDERR "Test suite not up-to-date. Please install the test suite that matches this\n".
"version of HeaderDoc by downloading the source tarball from opensource.apple.com\n".
"and running 'make realinstall' or 'make installsource'.\n";
$HeaderDoc::exitstatus = 1;
return (0, 1);
}
}
my %config = (
cCompiler => "/usr/bin/cc"
);
my $localConfigFileName = "headerDoc2HTML.config";
my $preferencesConfigFileName = "com.apple.headerDoc2HTML.config";
my $CWD = cwd();
my @configFiles = ($devtoolsPreferencesPath.$pathSeparator.$preferencesConfigFileName, $systemPreferencesPath.$pathSeparator.$preferencesConfigFileName, $usersPreferencesPath.$pathSeparator.$preferencesConfigFileName, $Bin.$pathSeparator.$localConfigFileName, $CWD.$pathSeparator.$localConfigFileName);
%config = &updateHashFromConfigFiles(\%config,\@configFiles);
$HeaderDoc::c_compiler = $config{cCompiler};
print STDERR "Using C compiler: ".$HeaderDoc::c_compiler."\n";
if ($#args == -1) {
my ($pyok, $pybad) = HeaderDoc::PythonParse::runPythonSpaceTests();
my ($macrook, $macrobad) = HeaderDoc::MacroFilter::run_macro_filter_tests();
my ($resolvelinksok, $resolvelinksbad) = runResolveLinksTests();
$ok_count += ($pyok + $macrook + $resolvelinksok);
$fail_count += ($pybad + $macrobad + $resolvelinksbad);
my $testdir = $HeaderDoc::testdir;
print "-= Running parser tests =-\n\n";
opendir(DIR, "$testdir/parser_tests");
@testlist = grep(/\.test$/,readdir(DIR));
closedir(DIR);
map(s/^/$testdir\/parser_tests\//, @testlist);
my $dump;
if ($mode eq "dump" || $mode eq "dump_parser") {
$dump = 1;
} else {
$dump = 0;
}
my ($newok, $newfail) = runtestlist(\@testlist, $dump, $update, $force);
$ok_count += $newok;
$fail_count += $newfail;
print "-= Running C preprocessor tests =-\n\n";
opendir(DIR, "$testdir/c_preprocessor_tests");
@testlist = grep(/\.test$/,readdir(DIR));
closedir(DIR);
map(s/^/$testdir\/c_preprocessor_tests\//, @testlist);
if ($mode eq "dump" || $mode eq "dump_cpp") {
$dump = 1;
} else {
$dump = 0;
}
($newok, $newfail) = runtestlist(\@testlist, $dump, $update, $force);
$ok_count += $newok;
$fail_count += $newfail;
} else {
my $dump;
if ($mode eq "dump") {
$dump = 1;
} else {
$dump = 0;
}
my ($newok, $newfail) = runtestlist($argref, $dump, $update, $force);
$ok_count += $newok;
$fail_count += $newfail;
}
print "\n\n-= SUMMARY =-\n\n";
print "Tests passed: $ok_count\n";
print "Tests failed: $fail_count\n";
print "Percent passed: ";
if ($fail_count != 0) {
print "\e[31m";
} else {
print "\e[32m";
}
if ($ok_count || $fail_count) {
print "".(($ok_count / ($fail_count + $ok_count)) * 100)."\%\n";
} else {
print "NaN\n";
}
print "\e[39m\n";
if ($fail_count) { $HeaderDoc::exitstatus = 1; }
}
sub runtestlist
{
my $testlistref = shift;
my @testlist = @{$testlistref};
my $dump = shift;
my $update = shift;
my $force = shift;
my $ok_count = 0;
my $fail_count = 0;
my @ignore_re = ();
foreach my $filename (sort {uc($a) cmp uc($b)} @testlist) {
if ($filename !~ /\.test$/) {
print STDERR "$filename does not appear to be a test. Skipping.\n";
next;
}
my $test = HeaderDoc::Test->new();
$test->readFromFile($filename);
my $plist = $filename;
$plist =~ s/\.test$/\.plist/g;
if (! -f $plist) {
$test->writeToPlist($filename);
}
print "Test \"".$test->{NAME}."\": ";
my $coretestfail = $test->runTest(\@ignore_re);
if ($coretestfail) {
die("\nTest suite aborted. Utilities tests failed.\n");
}
if ($dump) {
print "RESULTS DUMP:\n".$test->{RESULT}."\n";
}
if ((($test->{RESULT} ne $test->{EXPECTED_RESULT}) ||
($test->{RESULT_ALLDECS} ne $test->{EXPECTED_RESULT_ALLDECS})) &&
($test->{FILTERED_RESULT} eq $test->{EXPECTED_FILTERED_RESULT}) &&
($test->{FILTERED_RESULT_ALLDECS} eq $test->{EXPECTED_FILTERED_RESULT_ALLDECS})) {
print STDERR "Passed after filtering. Updating test automatically.\n";
$test->{EXPECTED_RESULT} = $test->{RESULT};
$test->{EXPECTED_RESULT_ALLDECS} = $test->{RESULT_ALLDECS};
$test->writeToFile($filename);
$test->writeToPlist($filename);
$ok_count++;
} elsif (($test->{FILTERED_RESULT} eq $test->{EXPECTED_FILTERED_RESULT}) &&
($test->{FILTERED_RESULT_ALLDECS} eq $test->{EXPECTED_FILTERED_RESULT_ALLDECS})) {
print "\e[32mOK\e[39m\n";
$ok_count++;
if ($force) {
$test->writeToFile($filename);
$test->writeToPlist($filename);
}
} else {
my $adonly = 0;
if ($test->{FILTERED_RESULT} eq $test->{EXPECTED_FILTERED_RESULT}) {
print "\e[31mFAILED (ALLDECS ONLY)\e[39m\n";
$adonly = 1;
if ($debugging || 1) {
if ($test->{RESULT_ALLDECS} eq $test->{EXPECTED_RESULT}) {
print STDERR "Results same as with alldecs off\n";
} else {
print STDERR "\@\@\@ ALLDECS RESULT:\@\@\@\n".$test->{RESULT_ALLDECS}."\n\n\@\@\@EXPECTED NON-ALLDECS RESULT:\@\@\@\n".$test->{EXPECTED_RESULT}."\n\n\@\@\@END OF RESULTS\@\@\@\n\n";
}
}
} else {
print "\e[31mFAILED\e[39m\n";
}
if ($dump || $update) { $test->showresults(); }
if ($update) {
my $continue_update = 1;
while ($continue_update) {
print "If these changes are expected, please type 'confirm' now.\n";
print "For more information, type 'more' now.\n";
print "To run 'diff' on the named objects, type 'less' now.\n";
print "To skip, type 'skip' now.\n";
print "To ignore a regexp, type 'ignore <expression>' now.\n";
$/ = "\n";
my $temp = <STDIN>;
if ($temp =~ /^\s*less\s*$/) {
my $addata = "";
my $adexpdata = "";
print "\nTest \"".$test->{NAME}."\":\n";
if ($adonly) {
print "\e[31m";
print STDERR "******** DUMPING ALLDECS RESULT ********";
print "\e[39m\n";
$adexpdata = $test->{EXPECTED_RESULT};
$addata = $test->{RESULT};
$test->{EXPECTED_RESULT} = $test->{EXPECTED_RESULT_ALLDECS};
$test->{RESULT} = $test->{RESULT_ALLDECS};
}
$test->showresults(-1);
if ($adonly) {
$test->{EXPECTED_RESULT} = $adexpdata;
$test->{RESULT} = $addata;
}
} elsif ($temp =~ /^\s*more\s*$/) {
print "\nTest \"".$test->{NAME}."\":\n";
$test->showresults(1);
$test->dbprint();
} elsif ($temp =~ /^\s*confirm\s*$/) {
$test->{EXPECTED_RESULT} = $test->{RESULT};
$test->{EXPECTED_RESULT_ALLDECS} = $test->{RESULT_ALLDECS};
$test->writeToFile($filename);
$test->writeToPlist($filename);
$ok_count++; $continue_update = 0;
} elsif ($temp =~ /^\s*skip\s*$/) {
$fail_count++; $continue_update = 0;
} elsif ($temp =~ s/^\s*ignore\s*//s) {
$temp =~ s/[\n\r]*$//s;
push(@ignore_re, $temp);
if (($test->{FILTERED_RESULT} eq $test->{EXPECTED_FILTERED_RESULT}) &&
($test->{FILTERED_RESULT_ALLDECS} eq $test->{EXPECTED_FILTERED_RESULT_ALLDECS})) {
print STDERR "It passes now.\n";
$test->{EXPECTED_RESULT} = $test->{RESULT};
$test->{EXPECTED_RESULT_ALLDECS} = $test->{RESULT_ALLDECS};
$test->writeToFile($filename);
$test->writeToPlist($filename);
$ok_count++; $continue_update = 0;
} else {
print STDERR "Still failed. (At some point, re-running a test will work, but not yet.)\n";
}
} else {
$temp =~ s/\n$//s;
print "Unknown response \"$temp\"\n";
}
}
} else {
$fail_count++;
}
}
}
return ($ok_count, $fail_count);
}
sub setTOCFormat
{
my $format = shift;
$format =~ s/\s*//sg;
if ($HeaderDoc::flagDashF) {
return;
}
if ($format =~ /default/i || $format =~ /div/i) {
$HeaderDoc::newTOC = 5;
} elsif ($format =~ /iframes/i) {
$HeaderDoc::newTOC = 0;
$HeaderDoc::use_iframes = 1;
} elsif ($format =~ /frames/i) {
$HeaderDoc::newTOC = 0;
$HeaderDoc::use_iframes = 0;
} else {
print STDERR "Unknown TOC format \"$format\"\n";
}
if ($HeaderDoc::use_iframes || $HeaderDoc::newTOC) {
$HeaderDoc::ClassAsComposite = 1;
} elsif ($HeaderDoc::flagDashC == -1) {
$HeaderDoc::ClassAsComposite = 0;
} else {
$HeaderDoc::ClassAsComposite = 1;
}
}
sub runResolveLinksTests
{
my $rltestdir = $HeaderDoc::testdir."/resolvelinks";
my $curdir = cwd();
my $okcount = 0;
my $failcount = 0;
print "-= Running resolveLinks tests =-\n\n";
chdir($rltestdir) || die("Could not change directories into resolveLinks test directory.\n");;
open(TESTRESULTS, "./runtests.sh --fromperl|") || die("Could not run resolveLinks tests.\n");
my $temp = $/;
$/ = "\n";
while (<TESTRESULTS>) {
my $line = $_;
if ($line =~ s/^PERLSTAT RESOLVELINKS:\s+//) {
my @parts = split(/\s/, $line);
$okcount = $parts[0];
$failcount = $parts[1];
} else {
print $line;
}
}
$/ = $temp;
close(TESTRESULTS);
chdir($curdir);
print "\n";
return ($okcount, $failcount);
}
sub printCPPHashes
{
my $tokenhashref = shift;
my $arghashref = shift;
my %tokenhash = %{$tokenhashref};
my %arghash = %{$arghashref};
print STDERR "DUMPING CPP HASHES\n";
foreach my $token (keys %tokenhash) {
print STDERR "CPP TOKEN $token -> ".$tokenhash{$token}."\n";
print STDERR " ARGS: ".$arghash{$token}."\n";
}
}