#! /usr/bin/perl -w
#
# Class name: APIOwner
# Synopsis: Abstract superclass for Header and OO structures
#
# Author: Matt Morse (matt@apple.com)
# Last Updated: $Date: 2004/03/01 21:59:08 $
#
# Method additions by SKoT McDonald Aug 2001
#
# Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved.
#
# @APPLE_LICENSE_HEADER_START@
#
# This file contains Original Code and/or Modifications of Original Code
# as defined in and that are subject to the Apple Public Source License
# Version 2.0 (the 'License'). You may not use this file except in
# compliance with the License. Please obtain a copy of the License at
# http://www.opensource.apple.com/apsl/ and read it before using this
# file.
#
# The Original Code and all software distributed under the License are
# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
# Please see the License for the specific language governing rights and
# limitations under the License.
#
# @APPLE_LICENSE_HEADER_END@
#
######################################################################
package HeaderDoc::APIOwner;
BEGIN {
foreach (qw(Mac::Files)) {
$MOD_AVAIL{$_} = eval "use $_; 1";
}
}
use HeaderDoc::HeaderElement;
use HeaderDoc::DBLookup;
use HeaderDoc::Utilities qw(findRelativePath safeName getAPINameAndDisc convertCharsForFileMaker printArray printHash resolveLink quote);
use strict;
use vars qw($VERSION @ISA);
$VERSION = '1.20';
# Inheritance
@ISA = qw(HeaderDoc::HeaderElement);
################ Portability ###################################
my $isMacOS;
my $pathSeparator;
if ($^O =~ /MacOS/i) {
$pathSeparator = ":";
$isMacOS = 1;
} else {
$pathSeparator = "/";
$isMacOS = 0;
}
################ General Constants ###################################
my $debugging = 0;
my $theTime = time();
my ($sec, $min, $hour, $dom, $moy, $year, @rest);
($sec, $min, $hour, $dom, $moy, $year, @rest) = localtime($theTime);
$moy++;
$year += 1900;
my $dateStamp = HeaderDoc::HeaderElement::strdate($moy, $dom, $year);
######################################################################
my $depth = 0;
# class variables and accessors
{
my $_copyrightOwner;
my $_defaultFrameName;
my $_compositePageName;
my $_htmlHeader;
my $_apiUIDPrefix;
# my $_headerObject;
sub copyrightOwner {
my $class = shift;
if (@_) {
$_copyrightOwner = shift;
}
return $_copyrightOwner;
}
sub defaultFrameName {
my $class = shift;
if (@_) {
$_defaultFrameName = shift;
}
return $_defaultFrameName;
}
sub compositePageName {
my $class = shift;
if (@_) {
$_compositePageName = shift;
}
return $_compositePageName;
}
sub htmlHeader {
my $class = shift;
if (@_) {
$_htmlHeader = shift;
}
return $_htmlHeader;
}
sub apiUIDPrefix {
my $class = shift;
if (@_) {
$_apiUIDPrefix = shift;
}
return $_apiUIDPrefix;
}
# sub headerObject {
# my $class = shift;
#
# if (@_) {
# $_headerObject = shift;
# }
# return $_headerObject;
# }
}
sub headerObject {
my $class = shift;
if (@_) {
$class->{HEADEROBJECT} = shift;
}
return $class->{HEADEROBJECT};
}
sub fix_date
{
$dateStamp = HeaderDoc::HeaderElement::strdate($moy, $dom, $year);
# print "fixed date stamp.\n";
}
sub new {
my($param) = shift;
my($class) = ref($param) || $param;
my $self = {};
bless($self, $class);
$self->_initialize();
return($self);
}
sub _initialize {
my($self) = shift;
$self->SUPER::_initialize();
$self->{OUTPUTDIR} = undef;
$self->{CONSTANTS} = ();
$self->{FUNCTIONS} = ();
$self->{METHODS} = ();
$self->{TYPEDEFS} = ();
$self->{STRUCTS} = ();
$self->{VARS} = ();
$self->{PDEFINES} = ();
$self->{ENUMS} = ();
$self->{CONSTANTSDIR} = undef;
$self->{DATATYPESDIR} = undef;
$self->{STRUCTSDIR} = undef;
$self->{VARSDIR} = undef;
$self->{FUNCTIONSDIR} = undef;
$self->{METHODSDIR} = undef;
$self->{PDEFINESDIR} = undef;
$self->{ENUMSDIR} = undef;
$self->{EXPORTSDIR} = undef;
$self->{EXPORTINGFORDB} = 0;
$self->{TOCTITLEPREFIX} = 'GENERIC_OWNER:';
$self->{HEADEROBJECT} = undef;
$self->{NAMESPACE} = "";
$self->{UPDATED} = "";
$self->{EXPLICITSUPER} = 0;
$self->{CLASSES} = ();
$self->{ISFRAMEWORK} = 0;
$self->{ISMERGED} = 0;
$self->{CCLASS} = 0;
$self->{HEADEROBJECT} = 0;
}
sub clone {
my $self = shift;
my $clone = undef;
if (@_) {
$clone = shift;
} else {
$clone = HeaderDoc::APIOwner->new();
}
$self->SUPER::clone($clone);
# now clone stuff specific to API owner
$clone->{OUTPUTDIR} = $self->{OUTPUTDIR};
$clone->{CONSTANTS} = ();
if ($self->{CONSTANTS}) {
my @params = @{$self->{CONSTANTS}};
foreach my $param (@params) {
my $cloneparam = $param->clone();
push(@{$clone->{CONSTANTS}}, $cloneparam);
$cloneparam->apiOwner($clone);
}
}
$clone->{FUNCTIONS} = ();
if ($self->{FUNCTIONS}) {
my @params = @{$self->{FUNCTIONS}};
foreach my $param (@params) {
my $cloneparam = $param->clone();
push(@{$clone->{FUNCTIONS}}, $cloneparam);
$cloneparam->apiOwner($clone);
}
}
$clone->{METHODS} = ();
if ($self->{METHODS}) {
my @params = @{$self->{METHODS}};
foreach my $param (@params) {
my $cloneparam = $param->clone();
push(@{$clone->{METHODS}}, $cloneparam);
$cloneparam->apiOwner($clone);
}
}
$clone->{TYPEDEFS} = ();
if ($self->{TYPEDEFS}) {
my @params = @{$self->{TYPEDEFS}};
foreach my $param (@params) {
my $cloneparam = $param->clone();
push(@{$clone->{TYPEDEFS}}, $cloneparam);
$cloneparam->apiOwner($clone);
}
}
$clone->{STRUCTS} = ();
if ($self->{STRUCTS}) {
my @params = @{$self->{STRUCTS}};
foreach my $param (@params) {
my $cloneparam = $param->clone();
push(@{$clone->{STRUCTS}}, $cloneparam);
$cloneparam->apiOwner($clone);
}
}
$clone->{VARS} = ();
if ($self->{VARS}) {
my @params = @{$self->{VARS}};
foreach my $param (@params) {
my $cloneparam = $param->clone();
push(@{$clone->{VARS}}, $cloneparam);
$cloneparam->apiOwner($clone);
}
}
$clone->{PDEFINES} = ();
if ($self->{PDEFINES}) {
my @params = @{$self->{PDEFINES}};
foreach my $param (@params) {
my $cloneparam = $param->clone();
push(@{$clone->{PDEFINES}}, $cloneparam);
$cloneparam->apiOwner($clone);
}
}
$clone->{ENUMS} = ();
if ($self->{ENUMS}) {
my @params = @{$self->{ENUMS}};
foreach my $param (@params) {
my $cloneparam = $param->clone();
push(@{$clone->{ENUMS}}, $cloneparam);
$cloneparam->apiOwner($clone);
}
}
$clone->{CONSTANTSDIR} = $self->{CONSTANTSDIR};
$clone->{DATATYPESDIR} = $self->{DATATYPESDIR};
$clone->{STRUCTSDIR} = $self->{STRUCTSDIR};
$clone->{VARSDIR} = $self->{VARSDIR};
$clone->{FUNCTIONSDIR} = $self->{FUNCTIONSDIR};
$clone->{METHODSDIR} = $self->{METHODSDIR};
$clone->{PDEFINESDIR} = $self->{PDEFINESDIR};
$clone->{ENUMSDIR} = $self->{ENUMSDIR};
$clone->{EXPORTSDIR} = $self->{EXPORTSDIR};
$clone->{EXPORTINGFORDB} = $self->{EXPORTINGFORDB};
$clone->{TOCTITLEPREFIX} = $self->{TOCTITLEPREFIX};
$clone->{HEADEROBJECT} = $self->{HEADEROBJECT};
$clone->{NAMESPACE} = $self->{NAMESPACE};
$clone->{UPDATED} = $self->{UPDATED};
$clone->{EXPLICITSUPER} = $self->{EXPLICITSUPER};
$clone->{CLASSES} = $self->{CLASSES};
$clone->{ISFRAMEWORK} = $self->{ISFRAMEWORK};
$clone->{ISMERGED} = $self->{ISMERGED};
$clone->{CCLASS} = $self->{CCLASS};
$clone->{HEADEROBJECT} = $self->{HEADEROBJECT} = 0;
return $clone;
}
sub CClass
{
my $self = shift;
if (@_) {
$self->{CCLASS} = shift;
}
return $self->{CCLASS};
}
sub isCOMInterface
{
return 0;
}
# /*! @function explicitSuper
# @abstract Test if superclass was specified in markup
# @discussion
# If the superclass is explicitly specified in the markup,
# it means that we'd like to include the functions,
# data types, etc. from the superclass in the subclass's
# documentation where possible.
# */
sub explicitSuper
{
my $self = shift;
if (@_) {
my $value = shift;
$self->{EXPLICITSUPER} = $value;
}
return $self->{EXPLICITSUPER};
}
# /*! @function isMerged
# @abstract get/set whether this class has had its superclass's members
# merged in yet (if applicable)
# */
sub isMerged
{
my $self = shift;
if (@_) {
my $value = shift;
$self->{ISMERGED} = $value;
}
return $self->{ISMERGED};
}
# /*! @function isFramework
# @abstract set whether this file contains framework documentation
# */
sub isFramework
{
my $self = shift;
if (@_) {
my $value = shift;
$self->{ISFRAMEWORK} = $value;
}
return $self->{ISFRAMEWORK};
}
# /*! @function classes
# @abstract return subclasses of this class (or classes within this header)
# */
sub classes
{
my $self = shift;
if (@_) {
@{ $self->{CLASSES} } = @_;
}
($self->{CLASSES}) ? return @{ $self->{CLASSES} } : return ();
}
# /*! @function protocols
# @abstract return protocols within this header
# */
sub protocols
{
return ();
}
# /*! @function categories
# @abstract return categories within this header
# */
sub categories
{
return ();
}
# Add this as part of Java subclass support.
# /*! @function addToClasses
# @abstract add to subclass list
# */
# sub addToClasses
# {
# }
sub outputDir {
my $self = shift;
if (@_) {
my $rootOutputDir = shift;
if (-e $rootOutputDir) {
if (! -d $rootOutputDir) {
die "Error: $rootOutputDir is not a directory. Exiting.\n\t$!\n";
} elsif (! -w $rootOutputDir) {
die "Error: Output directory $rootOutputDir is not writable. Exiting.\n$!\n";
}
} else {
unless (mkdir ("$rootOutputDir", 0777)) {
die ("Error: Can't create output folder $rootOutputDir.\n$!\n");
}
}
$self->{OUTPUTDIR} = $rootOutputDir;
$self->constantsDir("$rootOutputDir$pathSeparator"."Constants");
$self->datatypesDir("$rootOutputDir$pathSeparator"."DataTypes");
$self->structsDir("$rootOutputDir$pathSeparator"."Structs");
$self->functionsDir("$rootOutputDir$pathSeparator"."Functions");
$self->methodsDir("$rootOutputDir$pathSeparator"."Methods");
$self->varsDir("$rootOutputDir$pathSeparator"."Vars");
$self->pDefinesDir("$rootOutputDir$pathSeparator"."PDefines");
$self->enumsDir("$rootOutputDir$pathSeparator"."Enums");
$self->exportsDir("$rootOutputDir$pathSeparator"."Exports");
}
return $self->{OUTPUTDIR};
}
# /*! @function make_classref
# @abstract This function turns a classname into a pseudo-link
# @availability deprecated
# */
sub make_classref
{
my $self = shift;
my $classname = shift;
my $apiUIDPrefix = $self->apiUIDPrefix();
my $localDebug = 0;
my $retval = "";
# Not yet implemented
# my $lang = $self->lang();
my $lang = "c";
my $class = ref($self) || $self;
if ($class =~ /^HeaderDoc::CPPClass$/) {
$lang = "cpp";
} elsif ($class =~ /^HeaderDoc::ObjC/) {
$lang = "occ";
}
$retval = "//$apiUIDPrefix/$lang/cl/$classname";
print "make_classref: ref is $retval\n" if ($localDebug);;
return $retval;
}
sub tocTitlePrefix {
my $self = shift;
if (@_) {
$self->{TOCTITLEPREFIX} = shift;
}
return $self->{TOCTITLEPREFIX};
}
sub exportingForDB {
my $self = shift;
if (@_) {
$self->{EXPORTINGFORDB} = shift;
}
return $self->{EXPORTINGFORDB};
}
sub exportsDir {
my $self = shift;
if (@_) {
$self->{EXPORTSDIR} = shift;
}
return $self->{EXPORTSDIR};
}
sub constantsDir {
my $self = shift;
if (@_) {
$self->{CONSTANTSDIR} = shift;
}
return $self->{CONSTANTSDIR};
}
sub datatypesDir {
my $self = shift;
if (@_) {
$self->{DATATYPESDIR} = shift;
}
return $self->{DATATYPESDIR};
}
sub structsDir {
my $self = shift;
if (@_) {
$self->{STRUCTSDIR} = shift;
}
return $self->{STRUCTSDIR};
}
sub varsDir {
my $self = shift;
if (@_) {
$self->{VARSDIR} = shift;
}
return $self->{VARSDIR};
}
sub pDefinesDir {
my $self = shift;
if (@_) {
$self->{PDEFINESDIR} = shift;
}
return $self->{PDEFINESDIR};
}
sub enumsDir {
my $self = shift;
if (@_) {
$self->{ENUMSDIR} = shift;
}
return $self->{ENUMSDIR};
}
sub functionsDir {
my $self = shift;
if (@_) {
$self->{FUNCTIONSDIR} = shift;
}
return $self->{FUNCTIONSDIR};
}
sub methodsDir {
my $self = shift;
if (@_) {
$self->{METHODSDIR} = shift;
}
return $self->{METHODSDIR};
}
sub tocStringSub {
my $self = shift;
my $head = shift;
my $groupref = shift;
my $objref = shift;
my $compositePageName = shift;
my $baseref = shift;
my $composite = shift;
my $ignore_access = shift;
my $localDebug = 0;
my $class = ref($self) || $self;
my @groups = @{$groupref};
my @objs = @{$objref};
my $tocString = "";
if ($composite) {
$tocString .= "\n";
} else {
$tocString .= "\n";
}
foreach my $group (@groups) {
my $done_one = 0;
print "Sorting group $group\n" if ($localDebug);
my @groupobjs = ();
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @objs;
} else {
@tempobjs = @objs;
}
foreach my $obj (@tempobjs) {
if ($obj->group() eq $group) {
$done_one = 1;
push(@groupobjs, $obj);
}
}
if (!$done_one) {
# empty group
next;
}
my $preface = "";
if ($group eq "") {
$preface = " ";
} else {
# if ($done_one) { $tocString .= "
" }
$tocString .= "- $group:
- ";
}
my @Cs;
my @publics;
my @protecteds;
my @privates;
if ($HeaderDoc::sort_entries) {
@tempobjs = sort byAccessControl @groupobjs;
} else {
@tempobjs = @groupobjs;
}
foreach my $obj (@tempobjs) {
my $access = $obj->accessControl();
# print "ACCESS: $access\n";
if ($access =~ /public/ || $ignore_access){
push (@publics, $obj);
} elsif ($access =~ /protected/){
push (@protecteds, $obj);
} elsif ($access =~ /private/){
push (@privates, $obj);
} elsif ($access eq "") {
push (@Cs, $obj);
} else {
# assume public (e.g. C)
push (@publics, $obj);
}
}
if (@Cs) {
$tocString .= "\n";
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @Cs;
} else {
@tempobjs = @Cs;
}
foreach my $obj (@tempobjs) {
my $name = $obj->name();
if ($self->outputformat eq "hdxml") {
$tocString .= "XMLFIX$preface$name
\n";
} elsif ($self->outputformat eq "html") {
if ($composite) {
$tocString .= "$preface$name
\n";
} else {
$tocString .= "$preface$name
\n";
}
} else {
}
}
}
if (@publics) {
if ($class eq "HeaderDoc::Header" || $ignore_access) {
$tocString .= "\n";
} elsif ($self->outputformat eq "hdxml") {
$tocString .= "XMLFIXPublic
\n";
} elsif ($self->outputformat eq "html") {
$tocString .= "Public
\n";
} else {
}
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @publics;
} else {
@tempobjs = @publics;
}
foreach my $obj (@tempobjs) {
my $name = $obj->name();
if ($self->outputformat eq "hdxml") {
$tocString .= "XMLFIX$preface$name
\n";
} elsif ($self->outputformat eq "html") {
if ($composite) {
$tocString .= "$preface$name
\n";
} else {
$tocString .= "$preface$name
\n";
}
} else {
}
}
}
if (@protecteds) {
if ($class eq "HeaderDoc::Header" || $ignore_access) {
$tocString .= "\n";
} elsif ($self->outputformat eq "hdxml") {
$tocString .= "XMLFIXProtected
\n";
} elsif ($self->outputformat eq "html") {
$tocString .= "Protected
\n";
} else {
}
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @protecteds;
} else {
@tempobjs = @protecteds;
}
foreach my $obj (@tempobjs) {
my $name = $obj->name();
if ($self->outputformat eq "hdxml") {
$tocString .= "XMLFIX$preface$name
\n";
} elsif ($self->outputformat eq "html") {
if ($composite) {
$tocString .= "$preface$name
\n";
} else {
$tocString .= "$preface$name
\n";
}
} else {
}
}
}
if (@privates) {
if ($class eq "HeaderDoc::Header" || $ignore_access) {
$tocString .= "\n";
} elsif ($self->outputformat eq "hdxml") {
$tocString .= "XMLFIXPrivate
\n";
} elsif ($self->outputformat eq "html") {
$tocString .= "Private
\n";
} else {
}
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @privates;
} else {
@tempobjs = @privates;
}
foreach my $obj (@tempobjs) {
my $name = $obj->name();
if ($self->outputformat eq "hdxml") {
$tocString .= "XMLFIX$preface$name
\n";
} elsif ($self->outputformat eq "html") {
if ($composite) {
$tocString .= "$preface$name
\n";
} else {
$tocString .= "$preface$name
\n";
}
} else {
}
}
}
if (!($group eq "")) {
$tocString .= "
\n";
}
}
return $tocString;
}
sub inarray
{
my $name = shift;
my $arrayref = shift;
my @array = @{$arrayref};
foreach my $arrname (@array) {
if ($name eq $arrname) { return 1; }
}
return 0;
}
sub tocString {
my $self = shift;
my $contentFrameName = $self->filename();
my @classes = $self->classes();
my @protocols = $self->protocols();
my @categories = $self->categories();
my $class = ref($self) || $self;
my $xml = 0;
if ($self->outputformat() eq "hdxml") { $xml = 1; }
$contentFrameName =~ s/(.*)\.h/$1/;
$contentFrameName = &safeName(filename => $contentFrameName);
$contentFrameName = $contentFrameName . ".html";
# this could be a separate option, but really shouldn't be tied
# to $HeaderDoc::ClassAsComposite....
my $composite = 0;
my $compositePageName = HeaderDoc::APIOwner->compositePageName();
my $defaultFrameName = HeaderDoc::APIOwner->defaultFrameName();
if ($xml && $class ne "HeaderDoc::Header") { $compositePageName = $self->filename(); }
# @@@ WRONG PRINTABLE PAGE
if ($xml) {
$compositePageName =~ s/\.(h|i)$//;
$compositePageName .= ".xml";
}
my @funcs = $self->functions();
my @methods = $self->methods();
my @constants = $self->constants();
my @typedefs = $self->typedefs();
my @structs = $self->structs();
my @enums = $self->enums();
my @pDefines = $self->pDefines();
my @globals = $self->vars();
my $tocString = "";
if ($composite) {
$tocString .= "
\n";
} else {
$tocString .= "\n";
}
my @groups = ("");
my $localDebug = 0;
my @objs = ( @funcs, @methods, @constants, @typedefs, @structs, @enums,
@pDefines, @globals );
if ($HeaderDoc::sort_entries) { @objs = sort objGroup @objs; }
foreach my $obj (@objs) {
# warn "obj is $obj\n";
my $group = $obj->group();
if (!inarray($group, \@groups)) {
push (@groups, $group);
if ($localDebug) {
print "Added $group\n";
print "List is:";
foreach my $printgroup (@groups) {
print " $printgroup";
}
print "\n";
}
}
}
# output list of functions as TOC
if (@funcs) {
my $funchead = "Functions";
if ($class eq "HeaderDoc::CPPClass") {
$funchead = "Member Functions";
}
my $baseref = "Functions/Functions.html";
$tocString .= $self->tocStringSub($funchead, \@groups, \@funcs,
$compositePageName, $baseref, $composite, 0);
}
if (@methods) {
# $tocString .= "Methods
\n";
$tocString .= "\n";
foreach my $group (@groups) {
my $done_one = 0;
print "Sorting group $group\n" if ($localDebug);
my @groupmeths = ();
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @methods;
} else {
@tempobjs = @methods;
}
foreach my $obj (@tempobjs) {
if ($obj->group() eq $group) {
$done_one = 1;
push(@groupmeths, $obj);
}
}
if (!$done_one) {
# empty group
next;
}
if (!($group eq "")) {
# if ($done_one) { $tocString .= "
" }
$tocString .= "- $group:
- ";
}
my @classMethods;
my @instanceMethods;
foreach my $obj (sort byMethodType @groupmeths) {
my $type = $obj->isInstanceMethod();
if ($type =~ /NO/){
push (@classMethods, $obj);
} elsif ($type =~ /YES/){
push (@instanceMethods, $obj);
} else {
# assume instanceMethod
push (@instanceMethods, $obj);
}
}
if (@classMethods) {
if ($class eq "HeaderDoc::Header") {
$tocString .= "\n";
} elsif ($self->outputformat eq "hdxml") {
$tocString .= "XMLFIX
Class Methods
\n";
} elsif ($self->outputformat eq "html") {
$tocString .= "Class Methods
\n";
} else {
}
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @classMethods;
} else {
@tempobjs = @classMethods;
}
foreach my $obj (@tempobjs) {
my $name = $obj->name();
if ($self->outputformat eq "hdxml") {
$tocString .= "XMLFIX $name
\n";
} elsif ($self->outputformat eq "html") {
if ($composite) {
$tocString .= " $name
\n";
} else {
$tocString .= " $name
\n";
}
} else {
}
}
}
if (@instanceMethods) {
if ($class eq "HeaderDoc::Header") {
$tocString .= "\n";
} elsif ($self->outputformat eq "hdxml") {
$tocString .= "XMLFIXInstance Methods
\n";
} elsif ($self->outputformat eq "html") {
$tocString .= "Instance Methods
\n";
} else {
}
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @instanceMethods;
} else {
@tempobjs = @instanceMethods;
}
foreach my $obj (@tempobjs) {
my $name = $obj->name();
if ($self->outputformat eq "hdxml") {
$tocString .= "XMLFIX $name
\n";
} elsif ($self->outputformat eq "html") {
if ($composite) {
$tocString .= " $name
\n";
} else {
$tocString .= " $name
\n";
}
} else {
}
}
}
if (!($group eq "")) {
$tocString .= "
\n";
}
}
}
if (@typedefs) {
my $head = "Defined Types\n";
my $baseref = "DataTypes/DataTypes.html";
$tocString .= $self->tocStringSub($head, \@groups, \@typedefs,
$compositePageName, $baseref, $composite, 1);
}
if (@structs) {
my $head = "Structs and Unions\n";
my $baseref = "Structs/Structs.html";
$tocString .= $self->tocStringSub($head, \@groups, \@structs,
$compositePageName, $baseref, $composite, 1);
}
if (@constants) {
my $head = "Constants\n";
my $baseref = "Constants/Constants.html";
$tocString .= $self->tocStringSub($head, \@groups, \@constants,
$compositePageName, $baseref, $composite, 1);
}
if (@enums) {
my $head = "Enumerations\n";
my $baseref = "Enums/Enums.html";
$tocString .= $self->tocStringSub($head, \@groups, \@enums,
$compositePageName, $baseref, $composite, 1);
}
if (@pDefines) {
my $head = "#defines\n";
my $baseref = "PDefines/PDefines.html";
$tocString .= $self->tocStringSub($head, \@groups, \@pDefines,
$compositePageName, $baseref, $composite, 1);
}
if (@classes) {
my @realclasses = ();
my @comints = ();
foreach my $obj (@classes) {
if ($obj->isCOMInterface()) {
push(@comints, $obj);
} else {
push(@realclasses, $obj);
}
}
if (@realclasses) {
@classes = @realclasses;
$tocString .= "
Classes
\n";
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @classes;
} else {
@tempobjs = @classes;
}
foreach my $obj (@tempobjs) {
my $name = $obj->name();
my $safeName = $name;
# for now, always shorten long names since some files may be moved to a Mac for browsing
if (1 || $isMacOS) {$safeName = &safeName(filename => $name);};
$tocString .= " $name
\n";
}
}
if (@comints) {
@classes = @comints;
$tocString .= "COM Interfaces
\n";
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @classes;
} else {
@tempobjs = @classes;
}
foreach my $obj (@tempobjs) {
my $name = $obj->name();
my $safeName = $name;
# for now, always shorten long names since some files may be moved to a Mac for browsing
if (1 || $isMacOS) {$safeName = &safeName(filename => $name);};
$tocString .= " $name
\n";
}
}
}
if (@protocols) {
$tocString .= "Protocols
\n";
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @protocols;
} else {
@tempobjs = @protocols;
}
foreach my $obj (@tempobjs) {
my $name = $obj->name();
my $safeName = $name;
# for now, always shorten long names since some files may be moved to a Mac for browsing
if (1 || $isMacOS) {$safeName = &safeName(filename => $name);};
$tocString .= " $name
\n";
}
}
if (@categories) {
$tocString .= "Categories
\n";
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @categories;
} else {
@tempobjs = @categories;
}
foreach my $obj (@tempobjs) {
my $name = $obj->name();
my $safeName = $name;
# for now, always shorten long names since some files may be moved to a Mac for browsing
if (1 || $isMacOS) {$safeName = &safeName(filename => $name);};
$tocString .= " $name
\n";
}
}
if (@globals) {
my $globalname = "Globals";
if ($class ne "HeaderDoc::Header") {
$globalname = "Member Data";
}
my $baseref = "Vars/Vars.html";
$tocString .= $self->tocStringSub($globalname, \@groups, \@globals,
$compositePageName, $baseref, $composite, 0);
}
if ($class ne "HeaderDoc::Header") {
$tocString .= "
Other Reference
\n";
$tocString .= " Header
\n";
}
if (!$composite) {
$tocString .= "
[Printable HTML Page]\n";
}
my $availability = $self->availability();
my $updated = $self->updated();
if (length($availability)) {
$tocString .= "Availability: $availability
";
}
if (length($updated)) {
$tocString .= "
Updated: $updated
";
}
return $tocString;
}
sub enums {
my $self = shift;
if (@_) {
@{ $self->{ENUMS} } = @_;
}
($self->{ENUMS}) ? return @{ $self->{ENUMS} } : return ();
}
sub addToEnums {
my $self = shift;
if (@_) {
foreach my $item (@_) {
push (@{ $self->{ENUMS} }, $item);
}
}
return @{ $self->{ENUMS} };
}
sub pDefines {
my $self = shift;
if (@_) {
@{ $self->{PDEFINES} } = @_;
}
($self->{PDEFINES}) ? return @{ $self->{PDEFINES} } : return ();
}
sub addToPDefines {
my $self = shift;
if (@_) {
foreach my $item (@_) {
push (@{ $self->{PDEFINES} }, $item);
}
}
return @{ $self->{PDEFINES} };
}
sub constants {
my $self = shift;
if (@_) {
@{ $self->{CONSTANTS} } = @_;
}
($self->{CONSTANTS}) ? return @{ $self->{CONSTANTS} } : return ();
}
sub addToConstants {
my $self = shift;
if (@_) {
foreach my $item (@_) {
push (@{ $self->{CONSTANTS} }, $item);
}
}
return @{ $self->{CONSTANTS} };
}
sub functions {
my $self = shift;
if (@_) {
@{ $self->{FUNCTIONS} } = @_;
}
($self->{FUNCTIONS}) ? return @{ $self->{FUNCTIONS} } : return ();
}
sub addToFunctions {
my $self = shift;
my $localDebug = 0;
if (@_) {
foreach my $item (@_) {
foreach my $compare (@{ $self->{FUNCTIONS} }) {
my $name1 = $item->name();
my $name2 = $compare->name();
if ($item->name() eq $compare->name()) {
$item->conflict(1);
$compare->conflict(1);
print "$name1 = $name2\n" if ($localDebug);
}
}
push (@{ $self->{FUNCTIONS} }, $item);
}
}
return @{ $self->{FUNCTIONS} };
}
sub methods {
my $self = shift;
if (@_) {
@{ $self->{METHODS} } = @_;
}
($self->{METHODS}) ? return @{ $self->{METHODS} } : return ();
}
sub addToMethods {
my $self = shift;
if (@_) {
foreach my $item (@_) {
foreach my $compare (@{ $self->{METHODS} }) {
if ($item->name() eq $compare->name()) {
$item->conflict(1);
$compare->conflict(1);
}
}
push (@{ $self->{METHODS} }, $item);
}
}
return @{ $self->{METHODS} };
}
sub typedefs {
my $self = shift;
if (@_) {
@{ $self->{TYPEDEFS} } = @_;
}
($self->{TYPEDEFS}) ? return @{ $self->{TYPEDEFS} } : return ();
}
sub addToTypedefs {
my $self = shift;
if (@_) {
foreach my $item (@_) {
push (@{ $self->{TYPEDEFS} }, $item);
# print "added ".$item->name()." to $self.\n";
}
}
return @{ $self->{TYPEDEFS} };
}
sub structs {
my $self = shift;
if (@_) {
@{ $self->{STRUCTS} } = @_;
}
($self->{STRUCTS}) ? return @{ $self->{STRUCTS} } : return ();
}
sub addToStructs {
my $self = shift;
if (@_) {
foreach my $item (@_) {
push (@{ $self->{STRUCTS} }, $item);
}
}
return @{ $self->{STRUCTS} };
}
sub vars {
my $self = shift;
if (@_) {
@{ $self->{VARS} } = @_;
}
($self->{VARS}) ? return @{ $self->{VARS} } : return ();
}
sub addToVars {
my $self = shift;
if (@_) {
foreach my $item (@_) {
push (@{ $self->{VARS} }, $item);
}
}
return @{ $self->{VARS} };
}
sub fields {
my $self = shift;
if (@_) {
@{ $self->{FIELDS} } = @_;
}
($self->{FIELDS}) ? return @{ $self->{FIELDS} } : return ();
}
sub addToFields {
my $self = shift;
if (@_) {
push (@{$self->{FIELDS}}, @_);
}
return @{ $self->{FIELDS} };
}
sub namespace {
my $self = shift;
my $localDebug = 0;
if (@_) {
$self->{NAMESPACE} = shift;
}
print "namespace ".$self->{NAMESPACE}."\n" if ($localDebug);
return $self->{NAMESPACE};
}
sub availability {
my $self = shift;
if (@_) {
$self->{AVAILABILITY} = shift;
}
return $self->{AVAILABILITY};
}
sub updated {
my $self = shift;
my $localDebug = 0;
if (@_) {
my $updated = shift;
# $self->{UPDATED} = shift;
my $month; my $day; my $year;
$month = $day = $year = $updated;
print "updated is $updated\n" if ($localDebug);
if (!($updated =~ /\d\d\d\d-\d\d-\d\d/ )) {
if (!($updated =~ /\d\d-\d\d-\d\d\d\d/ )) {
if (!($updated =~ /\d\d-\d\d-\d\d/ )) {
# my $filename = $HeaderDoc::headerObject->filename();
my $filename = $self->filename();
my $linenum = $self->linenum();
print "$filename:$linenum:Bogus date format: $updated.\n";
print "Valid formats are MM-DD-YYYY, MM-DD-YY, and YYYY-MM-DD\n";
return $self->{UPDATED};
} else {
$month =~ s/(\d\d)-\d\d-\d\d/$1/smg;
$day =~ s/\d\d-(\d\d)-\d\d/$1/smg;
$year =~ s/\d\d-\d\d-(\d\d)/$1/smg;
my $century;
$century = `date +%C`;
$century *= 100;
$year += $century;
# $year += 2000;
print "YEAR: $year" if ($localDebug);
}
} else {
print "03-25-2003 case.\n" if ($localDebug);
$month =~ s/(\d\d)-\d\d-\d\d\d\d/$1/smg;
$day =~ s/\d\d-(\d\d)-\d\d\d\d/$1/smg;
$year =~ s/\d\d-\d\d-(\d\d\d\d)/$1/smg;
}
} else {
$year =~ s/(\d\d\d\d)-\d\d-\d\d/$1/smg;
$month =~ s/\d\d\d\d-(\d\d)-\d\d/$1/smg;
$day =~ s/\d\d\d\d-\d\d-(\d\d)/$1/smg;
}
$month =~ s/\n*//smg;
$day =~ s/\n*//smg;
$year =~ s/\n*//smg;
$month =~ s/\s*//smg;
$day =~ s/\s*//smg;
$year =~ s/\s*//smg;
# Check the validity of the modification date
my $invalid = 0;
my $mdays = 28;
if ($month == 2) {
if ($year % 4) {
$mdays = 28;
} elsif ($year % 100) {
$mdays = 29;
} elsif ($year % 400) {
$mdays = 28;
} else {
$mdays = 29;
}
} else {
my $bitcheck = (($month & 1) ^ (($month & 8) >> 3));
if ($bitcheck) {
$mdays = 31;
} else {
$mdays = 30;
}
}
if ($month > 12 || $month < 1) { $invalid = 1; }
if ($day > $mdays || $day < 1) { $invalid = 1; }
if ($year < 1970) { $invalid = 1; }
if ($invalid) {
# my $filename = $HeaderDoc::headerObject->filename();
my $filename = $self->filename();
my $linenum = $self->linenum();
print "$filename:$linenum:Invalid date (year = $year, month = $month, day = $day).\n";
print "$filename:$linenum:Valid formats are MM-DD-YYYY, MM-DD-YY, and YYYY-MM-DD\n";
return $self->{UPDATED};
} else {
$self->{UPDATED} =HeaderDoc::HeaderElement::strdate($month, $day, $year);
}
}
return $self->{UPDATED};
}
##################################################################
sub createMetaFile {
my $self = shift;
my $outDir = $self->outputDir();
my $outputFile = "$outDir$pathSeparator"."book.xml";
my $text = $self->metaFileText();
open(OUTFILE, ">$outputFile") || die "Can't write $outputFile. \n$!\n";
if ($isMacOS) {MacPerl::SetFileInfo('MSIE', 'TEXT', "$outputFile");};
print OUTFILE "$text";
close OUTFILE;
}
sub createFramesetFile {
my $self = shift;
my $docNavigatorComment = $self->docNavigatorComment();
my $class = ref($self);
my $defaultFrameName = $class->defaultFrameName();
my $filename = $self->filename();
my $name = $self->name();
my $title = $filename;
if (!length($name)) {
$name = "$filename";
} else {
$title = "$name ($filename)";
}
my $outDir = $self->outputDir();
my $outputFile = "$outDir$pathSeparator$defaultFrameName";
my $rootFileName = $self->filename();
$rootFileName =~ s/(.*)\.h/$1/;
$rootFileName = &safeName(filename => $rootFileName);
my $compositePageName = $self->compositePageName();
my $composite = $HeaderDoc::ClassAsComposite;
if ($class eq "HeaderDoc::Header") {
$composite = 0;
}
open(OUTFILE, ">$outputFile") || die "Can't write $outputFile. \n$!\n";
if ($isMacOS) {MacPerl::SetFileInfo('MSIE', 'TEXT', "$outputFile");};
print OUTFILE "\n";
print OUTFILE "
\n Documentation for $title\n \n\n";
print OUTFILE "\n";
print OUTFILE "$docNavigatorComment\n";
close OUTFILE;
}
# Overridden by subclasses to return HTML comment that identifies the
# index file (Header vs. Class, name, etc.). gatherHeaderDoc uses this
# information to create a master TOC of the generated doc.
#
sub docNavigatorComment {
return "";
}
sub createTOCFile {
my $self = shift;
my $rootDir = $self->outputDir();
my $tocTitlePrefix = $self->tocTitlePrefix();
my $outputFileName = "toc.html";
my $outputFile = "$rootDir$pathSeparator$outputFileName";
my $fileString = $self->tocString();
my $filename = $self->filename();
my $name = $self->name();
my $title = $filename;
if (!length($name)) {
$name = "$filename";
} elsif ($name eq $filename) {
$name = "$filename";
} else {
$title = "$name ($filename)";
}
open(OUTFILE, ">$outputFile") || die "Can't write $outputFile.\n$!\n";
if ($isMacOS) {MacPerl::SetFileInfo('MSIE', 'TEXT', "$outputFile");};
print OUTFILE "\n";
print OUTFILE "";
print OUTFILE $self->styleSheet();
print OUTFILE "\n Documentation for $title\n \n\n";
print OUTFILE "\n";
print OUTFILE "";
print OUTFILE "| |
";
print OUTFILE "
";
print OUTFILE "\n";
print OUTFILE "| | $tocTitlePrefix |
\n";
print OUTFILE "| | | $name |
\n";
print OUTFILE " | \n";
print OUTFILE $fileString;
print OUTFILE " |
\n";
print OUTFILE "
\n";
print OUTFILE "\n";
close OUTFILE;
}
sub calcDepth
{
my $filename = shift;
my $base = $HeaderDoc::headerObject->outputDir();
my $origfilename = $filename;
my $localDebug = 0;
$filename =~ s/^\Q$base//;
my @parts = split(/\//, $filename);
# Modify global depth.
$depth = (scalar @parts)-1;
warn("Filename: $origfilename; Depth: $depth\n") if ($localDebug);
return $depth;
}
sub createContentFile {
my $self = shift;
my $class = ref($self);
my $copyrightOwner = $class->copyrightOwner();
my $filename = $self->filename();
my $name = $self->name();
my $title = $filename;
if (!length($name)) {
$name = "$filename";
} else {
$title = "$name ($filename)";
}
my $rootFileName = $self->filename();
if ($class eq "HeaderDoc::Header") {
my $headercopyright = $self->headerCopyrightOwner();
if (!($headercopyright eq "")) {
$copyrightOwner = $headercopyright;
}
}
my $HTMLmeta = "";
if ($class eq "HeaderDoc::Header") {
$HTMLmeta = $self->HTMLmeta();
}
if ($self->outputformat() eq "html") {
$HTMLmeta .= $self->styleSheet();
}
my $fileString = "";
$rootFileName =~ s/(.*)\.h/$1/;
# for now, always shorten long names since some files may be moved to a Mac for browsing
if (1 || $isMacOS) {$rootFileName = &safeName(filename => $rootFileName);};
my $outputFileName = "$rootFileName.html";
my $rootDir = $self->outputDir();
my $outputFile = "$rootDir$pathSeparator$outputFileName";
calcDepth($outputFile);
open (OUTFILE, ">$outputFile") || die "Can't write header-wide content page $outputFile. \n$!\n";
if ($isMacOS) {MacPerl::SetFileInfo('MSIE', 'TEXT', "$outputFile");};
my $headerDiscussion = $self->discussion();
my $headerAbstract = $self->abstract();
if ((!length($headerDiscussion)) && (!length($headerAbstract))) {
my $linenum = $self->linenum();
warn "$filename:$linenum: No header or class discussion/abstract found. Creating dummy file for default content page.\n";
$headerAbstract .= "Use the links in the table of contents to the left to access documentation.
\n";
}
$fileString .= "\n";
$fileString .= "
\n API Documentation\n $HTMLmeta \n\n\n";
if ($HeaderDoc::insert_header) {
$fileString .= "\n";
$fileString .= $self->htmlHeader()."\n";
$fileString .= "\n";
}
$fileString .= "$name
\n";
if (length($headerAbstract)) {
# $fileString .= "Abstract: $headerAbstract
\n";
if ($self->can("isFramework") && $self->isFramework()) {
$fileString .= "\n";
}
$fileString .= "$headerAbstract\n";
if ($self->can("isFramework") && $self->isFramework()) {
$fileString .= "\n";
}
$fileString .= "
\n";
}
my $namespace = $self->namespace();
my $availability = $self->availability();
my $updated = $self->updated();
if (length($updated) || length($namespace)) {
$fileString .= "\n";
}
if (length($namespace)) {
$fileString .= "Namespace: $namespace
\n";
}
if (length($availability)) {
$fileString .= "Availability: $availability
\n";
}
if (length($updated)) {
$fileString .= "Updated: $updated
\n";
}
my $short_attributes = $self->getAttributes(0);
my $long_attributes = $self->getAttributes(1);
my $list_attributes = $self->getAttributeLists();
if (length($short_attributes)) {
$fileString .= "$short_attributes";
}
if (length($list_attributes)) {
$fileString .= "$list_attributes";
}
if (length($updated) || length($availability) || length($namespace) || length($headerAbstract) || length($short_attributes) || length($list_attributes)) {
$fileString .= "\n";
$fileString .= "
\n";
}
if ($self->can("isFramework") && $self->isFramework()) {
$fileString .= "\n";
}
$fileString .= "$headerDiscussion\n";
if ($self->can("isFramework") && $self->isFramework()) {
$fileString .= "\n";
}
$fileString .= "
\n";
if (length($long_attributes)) {
$fileString .= "$long_attributes";
}
my @fields = $self->fields();
if (@fields) {
$fileString .= "
Template Parameter Descriptions
";
# print "\nGOT fields.\n";
# $fileString .= "";
# $fileString .= "| Name | Description |
";
$fileString .= "";
for my $field (@fields) {
my $name = $field->name();
my $desc = $field->discussion();
# print "field $name $desc\n";
# $fileString .= "| $name | $desc |
";
$fileString .= "- $name
- $desc
";
}
# $fileString .= "
\n";
$fileString .= "\n";
}
$fileString .= "
";
$fileString .= "© $copyrightOwner " if (length($copyrightOwner));
my $filedate = $self->updated();
if (length($filedate)) {
$fileString .= "(Last Updated $filedate)\n";
} else {
$fileString .= "(Last Updated $dateStamp)\n";
}
$fileString .= "
";
$fileString .= "HTML documentation generated by HeaderDoc\n";
$fileString .= "\n";
$fileString .= "\n\n";
print OUTFILE $self->fixup_inheritDoc(toplevel_html_fixup_links($self, $fileString));
close OUTFILE;
}
sub writeHeaderElements {
my $self = shift;
my $rootOutputDir = $self->outputDir();
my $functionsDir = $self->functionsDir();
my $methodsDir = $self->methodsDir();
my $dataTypesDir = $self->datatypesDir();
my $structsDir = $self->structsDir();
my $constantsDir = $self->constantsDir();
my $varsDir = $self->varsDir();
my $enumsDir = $self->enumsDir();
my $pDefinesDir = $self->pDefinesDir();
if (! -e $rootOutputDir) {
unless (mkdir ("$rootOutputDir", 0777)) {die ("Can't create output folder $rootOutputDir. \n$!");};
}
# pre-process everything to make sure we don't have any unregistered
# api refs.
my $junk = "";
if ($self->functions()) {$junk = $self->_getFunctionDetailString(0);}
if ($self->methods()) {$junk = $self->_getMethodDetailString(0);}
if ($self->constants()) {$junk = $self->_getConstantDetailString();}
if ($self->typedefs()) {$junk = $self->_getTypedefDetailString();}
if ($self->structs()) {$junk = $self->_getStructDetailString();}
if ($self->vars()) {$junk = $self->_getVarDetailString();}
if ($self->enums()) {$junk = $self->_getEnumDetailString();}
if ($self->pDefines()) {$junk = $self->_getPDefineDetailString();}
if ($self->functions()) {
if (! -e $functionsDir) {
unless (mkdir ("$functionsDir", 0777)) {die ("Can't create output folder $functionsDir. \n$!");};
}
$self->writeFunctions();
}
if ($self->methods()) {
if (! -e $methodsDir) {
unless (mkdir ("$methodsDir", 0777)) {die ("Can't create output folder $methodsDir. \n$!");};
}
$self->writeMethods();
}
if ($self->constants()) {
if (! -e $constantsDir) {
unless (mkdir ("$constantsDir", 0777)) {die ("Can't create output folder $constantsDir. \n$!");};
}
$self->writeConstants();
}
if ($self->typedefs()) {
if (! -e $dataTypesDir) {
unless (mkdir ("$dataTypesDir", 0777)) {die ("Can't create output folder $dataTypesDir. \n$!");};
}
$self->writeTypedefs();
}
if ($self->structs()) {
if (! -e $structsDir) {
unless (mkdir ("$structsDir", 0777)) {die ("Can't create output folder $structsDir. \n$!");};
}
$self->writeStructs();
}
if ($self->vars()) {
if (! -e $varsDir) {
unless (mkdir ("$varsDir", 0777)) {die ("Can't create output folder $varsDir. \n$!");};
}
$self->writeVars();
}
if ($self->enums()) {
if (! -e $enumsDir) {
unless (mkdir ("$enumsDir", 0777)) {die ("Can't create output folder $enumsDir. \n$!");};
}
$self->writeEnums();
}
if ($self->pDefines()) {
if (! -e $pDefinesDir) {
unless (mkdir ("$pDefinesDir", 0777)) {die ("Can't create output folder $pDefinesDir. \n$!");};
}
$self->writePDefines();
}
}
sub writeHeaderElementsToXMLPage { # All API in a single XML page
my $self = shift;
my $class = ref($self);
my $compositePageName = $self->filename();
$compositePageName =~ s/\.(h|i)$//;
$compositePageName .= ".xml";
my $rootOutputDir = $self->outputDir();
my $name = $self->name();
my $XMLPageString = $self->_getXMLPageString();
my $outputFile = $rootOutputDir.$pathSeparator.$compositePageName;
# print "cpn = $compositePageName\n";
if (! -e $rootOutputDir) {
unless (mkdir ("$rootOutputDir", 0777)) {die ("Can't create output folder $rootOutputDir. $!");};
}
$self->_createXMLOutputFile($outputFile, xml_fixup_links($self, $XMLPageString), "$name");
}
sub writeHeaderElementsToCompositePage { # All API in a single HTML page -- for printing
my $self = shift;
my $class = ref($self);
my $compositePageName = $class->compositePageName();
my $rootOutputDir = $self->outputDir();
my $name = $self->name();
my $compositePageString = $self->_getCompositePageString();
$compositePageString = $self->stripAppleRefs($compositePageString);
my $outputFile = $rootOutputDir.$pathSeparator.$compositePageName;
if (! -e $rootOutputDir) {
unless (mkdir ("$rootOutputDir", 0777)) {die ("Can't create output folder $rootOutputDir. $!");};
}
my $processed_string = toplevel_html_fixup_links($self, $compositePageString);
$self->_createHTMLOutputFile($outputFile, $processed_string, "$name");
}
sub _getXMLPageString {
my $self = shift;
my $name = $self->name();
my $compositePageString;
my $contentString;
my $abstract = $self->XMLabstract();
if (length($abstract)) {
$compositePageString .= "";
$compositePageString .= $abstract;
$compositePageString .= "\n";
}
my $discussion = $self->XMLdiscussion();
if (length($discussion)) {
$compositePageString .= "";
$compositePageString .= $discussion;
$compositePageString .= "\n";
}
$contentString= $self->_getClassXMLDetailString();
if (length($contentString)) {
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= $contentString;
}
$contentString= $self->_getCategoryXMLDetailString();
if (length($contentString)) {
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= $contentString;
}
$contentString= $self->_getProtocolXMLDetailString();
if (length($contentString)) {
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= $contentString;
}
$contentString= $self->_getFunctionXMLDetailString();
if (length($contentString)) {
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= "";
$compositePageString .= $contentString;
$compositePageString .= "\n";
}
$contentString= $self->_getMethodXMLDetailString();
if (length($contentString)) {
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= "";
$compositePageString .= $contentString;
$compositePageString .= "\n";
}
$contentString= $self->_getConstantXMLDetailString();
if (length($contentString)) {
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= "";
$compositePageString .= $contentString;
$compositePageString .= "\n";
}
$contentString= $self->_getTypedefXMLDetailString();
if (length($contentString)) {
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= "";
$compositePageString .= $contentString;
$compositePageString .= "\n";
}
$contentString= $self->_getStructXMLDetailString();
if (length($contentString)) {
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= "";
$compositePageString .= $contentString;
$compositePageString .= "\n";
}
$contentString= $self->_getVarXMLDetailString();
if (length($contentString)) {
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= "";
$compositePageString .= $contentString;
$compositePageString .= "\n";
}
$contentString = $self->_getEnumXMLDetailString();
if (length($contentString)) {
$compositePageString .= "";
$compositePageString .= $contentString;
$compositePageString .= "\n";
}
$contentString= $self->_getPDefineXMLDetailString();
if (length($contentString)) {
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= "";
$compositePageString .= $contentString;
$compositePageString .= "\n";
}
# $compositePageString =~ s/^\
\
$//smg;
# $compositePageString =~ s/\
/
/smg;
# global substitutions
$compositePageString =~ s/\//smig;
$compositePageString =~ s/\<\/h1\>//smig;
$compositePageString =~ s/\//smig;
$compositePageString =~ s/\<\/h2\>//smig;
$compositePageString =~ s/\//smig;
$compositePageString =~ s/\<\/h3\>//smig;
$compositePageString =~ s/\
//smig;
$compositePageString =~ s/\
//smig;
$compositePageString =~ s/<tt>//smig;
$compositePageString =~ s/<\/tt>//smig;
$compositePageString =~ s/<pre>//smig;
$compositePageString =~ s/<\/pre>//smig;
$compositePageString =~ s/ / /smig;
# note: in theory, the paragraph tag can be left open,
# which could break XML parsers. While this is common
# in web pages, it doesn't seem to be common in
# headerdoc comments, so ignoring it for now.
# case standardize tags.
$compositePageString =~ s///smig;
$compositePageString =~ s/<\/ul>/<\/ul>/smig;
$compositePageString =~ s///smig;
$compositePageString =~ s/<\/ol>/<\/ol>/smig;
$compositePageString =~ s/- /
- /smig;
$compositePageString =~ s/<\/li>/<\/li>/smig;
$compositePageString =~ s///smig;
$compositePageString =~ s/<\/b>/<\/b>/smig;
$compositePageString =~ s///smig;
$compositePageString =~ s/<\/i>/<\/i>/smig;
my @compositearray = split(/
- /i, $compositePageString);
my $newstring = "";
my $done_one = 0;
foreach my $listelement (@compositearray) {
# We depend on the fact that the page can't legally start with
# an
- tag. :-)
if (!($done_one)) {
$done_one = 1;
$newstring .= "$listelement";
# print "first\n";
} else {
# print "not first\n";
if ($listelement =~ /<\/[uo]l>/i) {
$done_one = 0;
my $insert = 0;
if ($listelement =~ /^<\/[uo]l>/i) {
$done_one = 1; $insert = 1;
}
my @elementbits = split(/<\/[uo]l>/i, $listelement);
my $newelement = "";
foreach my $elementbit (@elementbits) {
if ($done_one) {
if ($insert) {
$newelement .= "
";
}
if ($listelement =~ /<\/ul>/i) {
$newelement .= "
";
} else {
$newelement .= "";
}
$newelement .= "$elementbit";
} else {
$done_one = 1;
if (!($listelement =~ /<\/li>/i)) {
$insert = 1;
}
$newelement .= "$elementbit";
}
}
$done_one = 1;
$listelement = $newelement;
} else {
if (!($listelement =~ /<\/li>/i)) {
$listelement .= "";
}
}
$newstring .= "- ";
$newstring .= "$listelement";
}
}
$compositePageString = $newstring;
$newstring = "";
$done_one = 0;
my @compositearray = split(/(
)/i, $compositePageString);
foreach my $listelement (@compositearray) {
if (!$done_one) {
$done_one = 1;
$newstring .= $listelement;
} elsif ($listelement eq "
") {
$newstring .= $listelement;
} else {
if ($listelement =~ /^(.*?)<(.*?)>(.*)$/s) {
my $firstpart = $1;
my $tagpart = $2;
my $tailpart = $3;
if ($tagpart eq "/p") {
$newstring .= $listelement;
} elsif ($tagpart =~ /^\//) {
$newstring .= $firstpart;
$newstring .= "
<" . $tagpart . ">";
$newstring .= $tailpart;
}
} else {
$newstring .= $listelement;
$newstring .= "
";
}
}
}
$compositePageString = $newstring;
return $compositePageString;
}
sub _getCompositePageString {
my $self = shift;
my $name = $self->name();
my $compositePageString;
my $contentString;
my $abstract = $self->abstract();
if (length($abstract)) {
$compositePageString .= "Abstract
\n";
$compositePageString .= $abstract;
}
my $discussion = $self->discussion();
if (length($discussion)) {
$compositePageString .= "Discussion
\n";
$compositePageString .= $discussion;
}
if ((length($abstract)) || (length($discussion))) {
$compositePageString .= "
";
}
$contentString= $self->_getFunctionDetailString(1);
if (length($contentString)) {
$compositePageString .= "Functions
\n";
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= $contentString;
}
$contentString= $self->_getMethodDetailString(1);
if (length($contentString)) {
$compositePageString .= "Methods
\n";
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= $contentString;
}
$contentString= $self->_getConstantDetailString();
if (length($contentString)) {
$compositePageString .= "Constants
\n";
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= $contentString;
}
$contentString= $self->_getTypedefDetailString();
if (length($contentString)) {
$compositePageString .= "Typedefs
\n";
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= $contentString;
}
$contentString= $self->_getStructDetailString();
if (length($contentString)) {
$compositePageString .= "Structs and Unions
\n";
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= $contentString;
}
$contentString= $self->_getVarDetailString();
if (length($contentString)) {
$compositePageString .= "Globals
\n";
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= $contentString;
}
$contentString = $self->_getEnumDetailString();
if (length($contentString)) {
$compositePageString .= "Enumerations
\n";
$compositePageString .= $contentString;
}
$contentString= $self->_getPDefineDetailString();
if (length($contentString)) {
$compositePageString .= "#defines
\n";
$contentString = $self->stripAppleRefs($contentString);
$compositePageString .= $contentString;
}
return $compositePageString;
}
# apple_ref markup is a named anchor that uniquely identifies each API symbol. For example, an Objective-C
# class named Foo would have the anchor . This markup is already in the
# primary documentation pages, so we don't want duplicates in the composite pages, thus this method. See
# the APIAnchors.html file in HeaderDoc's documentation to learn more about apple_ref markup.
sub stripAppleRefs {
my $self = shift;
my $string = shift;
my $apiUIDPrefix = HeaderDoc::APIOwner->apiUIDPrefix();
$apiUIDPrefix = quote($apiUIDPrefix);
$string =~ s|(.*?)<\s*/a\s*>|$1|g;
return $string;
}
sub writeFunctions {
my $self = shift;
my $functionFile = $self->functionsDir().$pathSeparator."Functions.html";
$self->_createHTMLOutputFile($functionFile, $self->_getFunctionDetailString(0), "Functions");
}
sub _getFunctionDetailString {
my $self = shift;
my $composite = shift;
my @funcObjs = $self->functions();
my $contentString = "";
$contentString .= $self->_getFunctionEmbeddedTOC($composite);
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @funcObjs;
} else {
@tempobjs = @funcObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->documentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub _getFunctionXMLDetailString {
my $self = shift;
my @funcObjs = $self->functions();
my $contentString = "";
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @funcObjs;
} else {
@tempobjs = @funcObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->XMLdocumentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub _getClassXMLDetailString {
my $self = shift;
my @classObjs = $self->classes();
my $contentString = "";
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @classObjs;
} else {
@tempobjs = @classObjs;
}
foreach my $obj (@tempobjs) {
# print "outputting class ".$obj->name.".";
my $documentationBlock = $obj->XMLdocumentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub _getCategoryXMLDetailString {
my $self = shift;
my @classObjs = $self->categories();
my $contentString = "";
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @classObjs;
} else {
@tempobjs = @classObjs;
}
foreach my $obj (@tempobjs) {
# print "outputting category ".$obj->name.".";
my $documentationBlock = $obj->XMLdocumentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub _getProtocolXMLDetailString {
my $self = shift;
my @classObjs = $self->protocols();
my $contentString = "";
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @classObjs;
} else {
@tempobjs = @classObjs;
}
foreach my $obj (@tempobjs) {
# print "outputting protocol ".$obj->name.".";
my $documentationBlock = $obj->XMLdocumentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub writeMethods {
my $self = shift;
my $methodFile = $self->methodsDir().$pathSeparator."Methods.html";
$self->_createHTMLOutputFile($methodFile, $self->_getMethodDetailString(0), "Methods");
}
sub _getEmbeddedTOC
{
my $self = shift;
my $listref = shift;
my $typeFile = shift;
my $tag = shift;
my $compositePage = shift;
my $localDebug = 0;
print "CPAGE: $compositePage\n" if ($localDebug);
my @objlist = @{ $listref };
my $eTOCString = "";
my $class = ref($self) || $self;
my $localDebug = 0;
my $compositePageName = $self->compositePageName();
$eTOCString .= "\n";
print "My class is $class\n" if ($localDebug);
if (!@objlist) { return ""; }
if (!($#objlist)) { return ""; }
$eTOCString .= "\n";
foreach my $obj (@objlist) {
# print "@objlist\n";
# print "OBJ: $obj\n";
my $name = $obj->name();
my $abstract = $obj->abstract();
my $url = "";
my $target = "doc";
my $composite = $HeaderDoc::ClassAsComposite;
if ($class eq "HeaderDoc::Header") { $composite = 0; }
if ($compositePage) { $composite = 1; $target = "_top"; }
if ($composite) {
$url = "$compositePageName#$name"
} else {
$url = "$typeFile#$name"
}
my $parentclass = $obj->origClass();
if (length($parentclass)) { $parentclass .= "::"; }
if ($self->CClass()) {
# Don't do this for pseudo-classes.
$parentclass = "";
}
$eTOCString .= "- $parentclass$name
\n";
$eTOCString .= "- $abstract
\n";
}
$eTOCString .= "
\n";
print "etoc: $eTOCString\n" if ($localDebug);
return $eTOCString;
}
sub _getFunctionEmbeddedTOC
{
my $self = shift;
my $composite = shift;
my @functions = $self->functions();
return $self->_getEmbeddedTOC(\@functions, "Functions.html", "functions", $composite);
}
sub _getMethodEmbeddedTOC
{
my $self = shift;
my $composite = shift;
my @methods = $self->methods();
return $self->_getEmbeddedTOC(\@methods, "Methods.html", "methods", $composite);
}
sub _getMethodDetailString {
my $self = shift;
my $composite = shift;
my @methObjs = $self->methods();
my $contentString = "";
my $localDebug = 0;
$contentString .= $self->_getMethodEmbeddedTOC($composite);
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @methObjs;
} else {
@tempobjs = @methObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->documentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub _getMethodXMLDetailString {
my $self = shift;
my @methObjs = $self->methods();
my $contentString = "";
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @methObjs;
} else {
@tempobjs = @methObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->XMLdocumentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub writeConstants {
my $self = shift;
my $constantsFile = $self->constantsDir().$pathSeparator."Constants.html";
$self->_createHTMLOutputFile($constantsFile, $self->_getConstantDetailString(), "Constants");
}
sub _getConstantDetailString {
my $self = shift;
my @constantObjs = $self->constants();
my $contentString;
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @constantObjs;
} else {
@tempobjs = @constantObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->documentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub _getConstantXMLDetailString {
my $self = shift;
my @constantObjs = $self->constants();
my $contentString;
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @constantObjs;
} else {
@tempobjs = @constantObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->XMLdocumentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub writeTypedefs {
my $self = shift;
my $typedefsFile = $self->datatypesDir().$pathSeparator."DataTypes.html";
$self->_createHTMLOutputFile($typedefsFile, $self->_getTypedefDetailString(), "Defined Types");
}
sub _getTypedefDetailString {
my $self = shift;
my @typedefObjs = $self->typedefs();
my $contentString;
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @typedefObjs;
} else {
@tempobjs = @typedefObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->documentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub _getTypedefXMLDetailString {
my $self = shift;
my @typedefObjs = $self->typedefs();
my $contentString;
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @typedefObjs;
} else {
@tempobjs = @typedefObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->XMLdocumentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub writeStructs {
my $self = shift;
my $structsFile = $self->structsDir().$pathSeparator."Structs.html";
$self->_createHTMLOutputFile($structsFile, $self->_getStructDetailString(), "Structs");
}
sub _getStructDetailString {
my $self = shift;
my @structObjs = $self->structs();
my $contentString;
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @structObjs;
} else {
@tempobjs = @structObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->documentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub _getStructXMLDetailString {
my $self = shift;
my @structObjs = $self->structs();
my $contentString;
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @structObjs;
} else {
@tempobjs = @structObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->XMLdocumentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub writeVars {
my $self = shift;
my $varsFile = $self->varsDir().$pathSeparator."Vars.html";
$self->_createHTMLOutputFile($varsFile, $self->_getVarDetailString(), "Data Members");
}
sub _getVarDetailString {
my $self = shift;
my @varObjs = $self->vars();
my $contentString;
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @varObjs;
} else {
@tempobjs = @varObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->documentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub _getVarXMLDetailString {
my $self = shift;
my @varObjs = $self->vars();
my $contentString;
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @varObjs;
} else {
@tempobjs = @varObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->XMLdocumentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub writeEnums {
my $self = shift;
my $enumsFile = $self->enumsDir().$pathSeparator."Enums.html";
$self->_createHTMLOutputFile($enumsFile, $self->_getEnumDetailString(), "Enumerations");
}
sub _getEnumDetailString {
my $self = shift;
my @enumObjs = $self->enums();
my $contentString;
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @enumObjs;
} else {
@tempobjs = @enumObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->documentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub _getEnumXMLDetailString {
my $self = shift;
my @enumObjs = $self->enums();
my $contentString;
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @enumObjs;
} else {
@tempobjs = @enumObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->XMLdocumentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub writePDefines {
my $self = shift;
my $pDefinesFile = $self->pDefinesDir().$pathSeparator."PDefines.html";
$self->_createHTMLOutputFile($pDefinesFile, $self->_getPDefineDetailString(), "#defines");
}
sub _getPDefineDetailString {
my $self = shift;
my @pDefineObjs = $self->pDefines();
my $contentString;
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @pDefineObjs;
} else {
@tempobjs = @pDefineObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->documentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub _getPDefineXMLDetailString {
my $self = shift;
my @pDefineObjs = $self->pDefines();
my $contentString;
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @pDefineObjs;
} else {
@tempobjs = @pDefineObjs;
}
foreach my $obj (@tempobjs) {
my $documentationBlock = $obj->XMLdocumentationBlock();
$contentString .= $documentationBlock;
}
return $contentString;
}
sub writeExportsWithName {
my $self = shift;
my $name = shift;
my $exportsDir = $self->exportsDir();
my $functionsFile = $exportsDir.$pathSeparator.$name.".ftab";
my $methodsFile = $exportsDir.$pathSeparator.$name.".ftab";
my $parametersFile = $exportsDir.$pathSeparator.$name.".ptab";
my $structsFile = $exportsDir.$pathSeparator.$name.".stab";
my $fieldsFile = $exportsDir.$pathSeparator.$name.".mtab";
my $enumeratorsFile = $exportsDir.$pathSeparator.$name.".ktab";
my $funcString;
my $methString;
my $paramString;
my $dataTypeString;
my $typesFieldString;
my $enumeratorsString;
if (! -e $exportsDir) {
unless (mkdir ("$exportsDir", 0777)) {die ("Can't create output folder $exportsDir. $!");};
}
($funcString, $paramString) = $self->_getFunctionsAndParamsExportString();
($methString, $paramString) = $self->_getMethodsAndParamsExportString();
($dataTypeString, $typesFieldString) = $self->_getDataTypesAndFieldsExportString();
$enumeratorsString = $self->_getEnumeratorsExportString();
$self->_createExportFile($functionsFile, $funcString);
$self->_createExportFile($methodsFile, $methString);
$self->_createExportFile($parametersFile, $paramString);
$self->_createExportFile($structsFile, $dataTypeString);
$self->_createExportFile($fieldsFile, $typesFieldString);
$self->_createExportFile($enumeratorsFile, $enumeratorsString);
}
sub _getFunctionsAndParamsExportString {
my $self = shift;
my @funcObjs = $self->functions();
my $tmpString = "";
my @funcLines;
my @paramLines;
my $funcString;
my $paramString;
my $sep = "";
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @funcObjs;
} else {
@tempobjs = @funcObjs;
}
foreach my $obj (@tempobjs) {
my $funcName = $obj->name();
my $desc = $obj->discussion();
my $abstract = $obj->abstract();
my $declaration = $obj->declaration();
my @taggedParams = $obj->taggedParameters();
my @parsedParams = $obj->parsedParameters();
my $result = $obj->result();
my $funcID = HeaderDoc::DBLookup->functionIDForName($funcName);
# unused fields--declaring them for visibility in the string below
my $managerID = "";
my $funcEnglishName = "";
my $specialConsiderations = "";
my $versionNotes = "";
my $groupName = "";
my $order = "";
# Replace single internal carriage returns in fields with one space
# headerDoc2HTML already changes two \n's to \n
\n, so we'll
# just remove the breaks
foreach my $string ($desc, $abstract, $declaration, $result) {
$string =~ s/\n
\n/\n\n/g;
$string =~ s/([^\n])\n([^\n])/$1 $2/g;
}
$tmpString = $managerID.$sep.$funcID.$sep.$funcName.$sep.$funcEnglishName.$sep.$abstract.$sep.$desc.$sep.$result.$sep.$specialConsiderations.$sep.$versionNotes.$sep.$groupName.$sep.$order;
$tmpString = &convertCharsForFileMaker($tmpString);
$tmpString =~ s/$sep/\t/g;
push (@funcLines, "$tmpString");
if (@taggedParams) {
my %parsedParmNameToObjHash;
# make lookup hash of parsed params
foreach my $parsedParam (@parsedParams) {
$parsedParmNameToObjHash{$parsedParam->name()} = $parsedParam;
}
foreach my $taggedParam (@taggedParams) {
my $tName = $taggedParam->name();
my $pObj;
my $pos = "UNKNOWN_POSITION";
my $type = "UNKNOWN_TYPE";
if (exists $parsedParmNameToObjHash{$tName}) {
$pObj = $parsedParmNameToObjHash{$tName};
$pos = $pObj->position();
$type = $pObj->type();
} else {
# my $filename = $HeaderDoc::headerObject->name();
my $filename = $self->filename();
my $linenum = $self->linenum();
print "$filename:$linenum:---------------------------------------------------------------------------\n";
warn "$filename:$linenum:Tagged parameter '$tName' not found in declaration of function $funcName.\n";
warn "$filename:$linenum:Parsed declaration for $funcName is:\n$declaration\n";
warn "$filename:$linenum:Parsed params for $funcName are:\n";
foreach my $pp (@parsedParams) {
my $n = $pp->name();
print "$filename:$linenum:$n\n";
}
print "$filename:$linenum:---------------------------------------------------------------------------\n";
}
my $paramName = $taggedParam->name();
my $disc = $taggedParam->discussion();
$disc =~ s/\n
\n/\n\n/g;
$disc =~ s/([^\n])\n([^\n])/$1 $2/g;
my $tmpParamString = "";
$tmpParamString = $funcID.$sep.$funcName.$sep.$pos.$sep.$disc.$sep.$sep.$sep.$paramName.$sep.$type;
$tmpParamString = &convertCharsForFileMaker($tmpParamString);
$tmpParamString =~ s/$sep/\t/g;
push (@paramLines, "$tmpParamString");
}
}
}
$funcString = join ("\n", @funcLines);
$paramString = join ("\n", @paramLines);
$funcString .= "\n";
$paramString .= "\n";
return ($funcString, $paramString);
}
sub _getMethodsAndParamsExportString {
my $self = shift;
my @methObjs = $self->methods();
my $tmpString = "";
my @methLines;
my @paramLines;
my $methString;
my $paramString;
my $sep = "";
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @methObjs;
} else {
@tempobjs = @methObjs;
}
foreach my $obj (@tempobjs) {
my $methName = $obj->name();
my $desc = $obj->discussion();
my $abstract = $obj->abstract();
my $declaration = $obj->declaration();
my @taggedParams = $obj->taggedParameters();
my @parsedParams = $obj->parsedParameters();
my $result = $obj->result();
my $methID = HeaderDoc::DBLookup->methodIDForName($methName);
# unused fields--declaring them for visibility in the string below
my $managerID = "";
my $methEnglishName = "";
my $specialConsiderations = "";
my $versionNotes = "";
my $groupName = "";
my $order = "";
# Replace single internal carriage returns in fields with one space
# headerDoc2HTML already changes two \n's to \n
\n, so we'll
# just remove the breaks
foreach my $string ($desc, $abstract, $declaration, $result) {
$string =~ s/\n
\n/\n\n/g;
$string =~ s/([^\n])\n([^\n])/$1 $2/g;
}
$tmpString = $managerID.$sep.$methID.$sep.$methName.$sep.$methEnglishName.$sep.$abstract.$sep.$desc.$sep.$result.$sep.$specialConsiderations.$sep.$versionNotes.$sep.$groupName.$sep.$order;
$tmpString = &convertCharsForFileMaker($tmpString);
$tmpString =~ s/$sep/\t/g;
push (@methLines, "$tmpString");
if (@taggedParams) {
my %parsedParmNameToObjHash;
# make lookup hash of parsed params
foreach my $parsedParam (@parsedParams) {
$parsedParmNameToObjHash{$parsedParam->name()} = $parsedParam;
}
foreach my $taggedParam (@taggedParams) {
my $tName = $taggedParam->name();
my $pObj;
my $pos = "UNKNOWN_POSITION";
my $type = "UNKNOWN_TYPE";
if (exists $parsedParmNameToObjHash{$tName}) {
$pObj = $parsedParmNameToObjHash{$tName};
$pos = $pObj->position();
$type = $pObj->type();
} else {
# my $filename = $HeaderDoc::headerObject->name();
my $filename = $self->filename();
my $linenum = $self->linenum();
print "$filename:$linenum:---------------------------------------------------------------------------\n";
warn "$filename:$linenum:Tagged parameter '$tName' not found in declaration of method $methName.\n";
warn "$filename:$linenum:Parsed declaration for $methName is:\n$declaration\n";
warn "$filename:$linenum:Parsed params for $methName are:\n";
foreach my $pp (@parsedParams) {
my $n = $pp->name();
print "$filename:$linenum:$n\n";
}
print "$filename:$linenum:---------------------------------------------------------------------------\n";
}
my $paramName = $taggedParam->name();
my $disc = $taggedParam->discussion();
$disc =~ s/\n
\n/\n\n/g;
$disc =~ s/([^\n])\n([^\n])/$1 $2/g;
my $tmpParamString = "";
$tmpParamString = $methID.$sep.$methName.$sep.$pos.$sep.$disc.$sep.$sep.$sep.$paramName.$sep.$type;
$tmpParamString = &convertCharsForFileMaker($tmpParamString);
$tmpParamString =~ s/$sep/\t/g;
push (@paramLines, "$tmpParamString");
}
}
}
$methString = join ("\n", @methLines);
$paramString = join ("\n", @paramLines);
$methString .= "\n";
$paramString .= "\n";
return ($methString, $paramString);
}
sub _getDataTypesAndFieldsExportString {
my $self = shift;
my @structObjs = $self->structs();
my @typedefs = $self->typedefs();
my @constants = $self->constants();
my @enums = $self->enums();
my @dataTypeLines;
my @fieldLines;
my $dataTypeString;
my $fieldString;
my $sep = "";
my $tmpString = "";
my $contentString = "";
# unused fields -- here for clarity
my $englishName = "";
my $specialConsiderations = "";
my $versionNotes = "";
# get Enumerations
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @enums;
} else {
@tempobjs = @enums;
}
foreach my $obj (@tempobjs) {
my $name = $obj->name();
my $desc = $obj->discussion();
my $abstract = $obj->abstract();
my $declaration = $obj->declaration();
my $enumID = HeaderDoc::DBLookup->typeIDForName($name);
# Replace single internal carriage returns in fields with one space
# headerDoc2HTML already changes two \n's to \n
\n, so we'll
# just remove the breaks
foreach my $string ($desc, $abstract, $declaration) {
$string =~ s/\n
\n/\n\n/g;
$string =~ s/([^\n])\n([^\n])/$1 $2/g;
}
$tmpString = $enumID.$sep.$name.$sep.$englishName.$sep.$abstract.$sep.$desc.$sep.$specialConsiderations.$sep.$versionNotes."\n";
$tmpString = &convertCharsForFileMaker($tmpString);
$tmpString =~ s/$sep/\t/g;
push (@dataTypeLines, "$tmpString");
}
# get Constants
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @constants;
} else {
@tempobjs = @constants;
}
foreach my $obj (@tempobjs) {
my $name = $obj->name();
my $desc = $obj->discussion();
my $abstract = $obj->abstract();
my $constID = HeaderDoc::DBLookup->typeIDForName($name);
# Replace single internal carriage returns in fields with one space
# headerDoc2HTML already changes two \n's to \n
\n, so we'll
# just remove the breaks
foreach my $string ($desc, $abstract) {
$string =~ s/\n
\n/\n\n/g;
$string =~ s/([^\n])\n([^\n])/$1 $2/g;
}
$tmpString = $constID.$sep.$name.$sep.$englishName.$sep.$abstract.$sep.$desc.$sep.$specialConsiderations.$sep.$versionNotes."\n";
$tmpString = &convertCharsForFileMaker($tmpString);
$tmpString =~ s/$sep/\t/g;
push (@dataTypeLines, "$tmpString");
}
# get Structs and Unions
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @structObjs;
} else {
@tempobjs = @structObjs;
}
foreach my $obj (@tempobjs) {
my $name = $obj->name();
my $desc = $obj->discussion();
my $abstract = $obj->abstract();
my $declaration = $obj->declaration();
my @fields = $obj->fields();
my $structID = HeaderDoc::DBLookup->typeIDForName($name);
# Replace single internal carriage returns in fields with one space
# headerDoc2HTML already changes two \n's to \n
\n, so we'll
# just remove the breaks
foreach my $string ($desc, $abstract, $declaration) {
$string =~ s/\n
\n/\n\n/g;
$string =~ s/([^\n])\n([^\n])/$1 $2/g;
}
$tmpString = $structID.$sep.$name.$sep.$englishName.$sep.$abstract.$sep.$desc.$sep.$specialConsiderations.$sep.$versionNotes."\n";
$tmpString = &convertCharsForFileMaker($tmpString);
$tmpString =~ s/$sep/\t/g;
push (@dataTypeLines, "$tmpString");
if (@fields) {
foreach my $field (@fields) {
my $fName = $field->name();
my $discussion = $field->discussion();
$discussion =~ s/\n
\n/\n\n/g;
$discussion =~ s/([^\n])\n([^\n])/$1 $2/g;
my $pos = 0;
$pos = $self->_positionOfNameInBlock($fName, $declaration);
if (!$pos) {
# my $filename = $HeaderDoc::headerObject->name();
my $filename = $self->filename();
my $linenum = $self->linenum();
print "$filename:$linenum:---------------------------------------------------------------------------\n";
warn "$filename:$linenum:Tagged parameter '$fName' not found in declaration of struct $name.\n";
warn "$filename:$linenum:Declaration for $name is:\n$declaration\n";
print "$filename:$linenum:---------------------------------------------------------------------------\n";
$pos = "UNKNOWN_POSITION";
}
my $tmpFieldString = "";
$tmpFieldString = $structID.$sep.$name.$sep.$pos.$sep.$discussion.$sep.$sep.$sep.$fName;
$tmpFieldString = &convertCharsForFileMaker($tmpFieldString);
$tmpFieldString =~ s/$sep/\t/g;
push (@fieldLines, "$tmpFieldString");
}
}
}
# get Typedefs
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @typedefs;
} else {
@tempobjs = @typedefs;
}
foreach my $obj (@tempobjs) {
my $name = $obj->name();
my $desc = $obj->discussion();
my $abstract = $obj->abstract();
my $declaration = $obj->declaration();
my @fields = $obj->fields();
my $isFunctionPointer = $obj->isFunctionPointer();
my $typedefID = HeaderDoc::DBLookup->typeIDForName($name);
# Replace single internal carriage returns in fields with one space
# headerDoc2HTML already changes two \n's to \n
\n, so we'll
# just remove the breaks
foreach my $string ($desc, $abstract, $declaration) {
$string =~ s/\n
\n/\n\n/g;
$string =~ s/([^\n])\n([^\n])/$1 $2/g;
}
$tmpString = $typedefID.$sep.$name.$sep.$englishName.$sep.$abstract.$sep.$desc.$sep.$specialConsiderations.$sep.$versionNotes."\n";
$tmpString = &convertCharsForFileMaker($tmpString);
$tmpString =~ s/$sep/\t/g;
push (@dataTypeLines, "$tmpString");
if (@fields) {
foreach my $field (@fields) {
my $fName = $field->name();
my $discussion = $field->discussion();
$discussion =~ s/\n
\n/\n\n/g;
$discussion =~ s/([^\n])\n([^\n])/$1 $2/g;
my $pos = 0;
if ($isFunctionPointer) {
$pos = $self->_positionOfNameInFuncPtrDec($fName, $declaration);
} else {
$pos = $self->_positionOfNameInBlock($fName, $declaration);
}
if (!$pos) {
# my $filename = $HeaderDoc::headerObject->name();
my $filename = $self->filename();
my $linenum = $self->linenum();
print "$filename:$linenum:---------------------------------------------------------------------------\n";
warn "$filename:$linenum:Tagged parameter '$fName' not found in declaration of struct $name.\n";
warn "$filename:$linenum:Declaration for $name is:\n$declaration\n";
print "$filename:$linenum:---------------------------------------------------------------------------\n";
$pos = "UNKNOWN_POSITION";
}
my $tmpFieldString = "";
$tmpFieldString = $typedefID.$sep.$name.$sep.$pos.$sep.$discussion.$sep.$sep.$sep.$fName;
$tmpFieldString = &convertCharsForFileMaker($tmpFieldString);
$tmpFieldString =~ s/$sep/\t/g;
push (@fieldLines, "$tmpFieldString");
}
}
}
$dataTypeString = join ("\n", @dataTypeLines);
$fieldString = join ("\n", @fieldLines);
$dataTypeString .= "\n";
$fieldString .= "\n";
return ($dataTypeString, $fieldString);
}
sub _getEnumeratorsExportString {
my $self = shift;
my @enums = $self->enums();
my @fieldLines;
my $fieldString;
my $sep = "";
my $tmpString = "";
my $contentString = "";
# get Enumerations
my @tempobjs = ();
if ($HeaderDoc::sort_entries) {
@tempobjs = sort objName @enums;
} else {
@tempobjs = @enums;
}
foreach my $obj (@tempobjs) {
my $name = $obj->name();
my @constants = $obj->constants();
my $declaration = $obj->declaration();
my $enumID = HeaderDoc::DBLookup->typeIDForName($name);
if (@constants) {
foreach my $enumerator (@constants) {
my $fName = $enumerator->name();
my $discussion = $enumerator->discussion();
my $pos = 0;
$discussion =~ s/\n
\n/\n\n/g;
$discussion =~ s/([^\n])\n([^\n])/$1 $2/g;
$pos = $self->_positionOfNameInEnum($fName, $declaration);
if (!$pos) {
# my $filename = $HeaderDoc::headerObject->name();
my $filename = $self->filename();
my $linenum = $self->linenum();
print "$filename:$linenum:---------------------------------------------------------------------------\n";
warn "$filename:$linenum:Tagged parameter '$fName' not found in declaration of enum $name.\n";
warn "$filename:$linenum:Declaration for $name is:\n$declaration\n";
print "$filename:$linenum:---------------------------------------------------------------------------\n";
$pos = "UNKNOWN_POSITION";
}
my $tmpFieldString = "";
$tmpFieldString = $enumID.$sep.$name.$sep.$pos.$sep.$discussion.$sep.$sep.$sep.$fName;
$tmpFieldString = &convertCharsForFileMaker($tmpFieldString);
$tmpFieldString =~ s/$sep/\t/g;
push (@fieldLines, "$tmpFieldString");
}
}
}
$fieldString = join ("\n", @fieldLines);
$fieldString .= "\n";
return $fieldString;
}
# this is simplistic is various ways--should be made more robust.
sub _positionOfNameInBlock {
my $self = shift;
my $name = shift;
my $block = shift;
$block =~ s/\n/ /g;
my $pos = 0;
my $i = 0;
my @chunks = split (/;/, $block);
foreach my $string (@chunks) {
$i++;
$string = quotemeta($string);
if ($string =~ /$name/) {
$pos = $i;
last;
}
}
return $pos;
}
sub _positionOfNameInEnum {
my $self = shift;
my $name = shift;
my $block = shift;
$block =~ s/\n/ /g;
my $pos = 0;
my $i = 0;
my @chunks = split (/,/, $block);
foreach my $string (@chunks) {
$i++;
$string = quotemeta($string);
if ($string =~ /$name/) {
$pos = $i;
last;
}
}
return $pos;
}
sub _positionOfNameInFuncPtrDec {
my $self = shift;
my $name = shift;
my $dec = shift;
$dec =~ s/\n/ /g;
my @decParts = split (/\(/, $dec);
my $paramList = pop @decParts;
my $pos = 0;
my $i = 0;
my @chunks = split (/,/, $paramList);
foreach my $string (@chunks) {
$i++;
$string = quotemeta($string);
if ($string =~ /$name/) {
$pos = $i;
last;
}
}
return $pos;
}
sub _positionOfNameInMethPtrDec {
my $self = shift;
my $name = shift;
my $dec = shift;
$dec =~ s/\n/ /g;
my @decParts = split (/\(/, $dec);
my $paramList = pop @decParts;
my $pos = 0;
my $i = 0;
my @chunks = split (/,/, $paramList);
foreach my $string (@chunks) {
$i++;
$string = quotemeta($string);
if ($string =~ /$name/) {
$pos = $i;
last;
}
}
return $pos;
}
sub _createExportFile {
my $self = shift;
my $outputFile = shift;
my $fileString = shift;
open(OUTFILE, ">$outputFile") || die "Can't write $outputFile.\n";
if ($^O =~ /MacOS/i) {MacPerl::SetFileInfo('R*ch', 'TEXT', "$outputFile");};
print OUTFILE $fileString;
close OUTFILE;
}
sub _createXMLOutputFile {
my $self = shift;
my $class = ref($self);
my $copyrightOwner = $class->copyrightOwner();
my $outputFile = shift;
my $orig_fileString = shift;
my $heading = shift;
my $fullpath = $self->fullpath();
if ($class eq "HeaderDoc::Header") {
my $headercopyright = $self->headerCopyrightOwner();
if (!($headercopyright eq "")) {
$copyrightOwner = $headercopyright;
}
}
my $HTMLmeta = "";
if ($class eq "HeaderDoc::Header") {
$HTMLmeta = $self->HTMLmeta();
}
calcDepth($outputFile);
my $fileString = $self->xml_fixup_links($orig_fileString);
open(OUTFILE, ">$outputFile") || die "Can't write $outputFile.\n";
if ($^O =~ /MacOS/i) {MacPerl::SetFileInfo('MSIE', 'TEXT', "$outputFile");};
print OUTFILE "\n";
print OUTFILE "";
print OUTFILE "$heading\n";
# Need to get the C++ Class Abstract and Discussion....
# my $headerDiscussion = $self->discussion();
# my $headerAbstract = $self->abstract();
# print OUTFILE "$headerAbstract\n";
# print OUTFILE "$headerDiscussion\n";
print OUTFILE $fileString;
print OUTFILE "© $copyrightOwner" if (length($copyrightOwner));
print OUTFILE "$dateStamp\n";
print OUTFILE "";
close OUTFILE;
}
sub _createHTMLOutputFile {
my $self = shift;
my $class = ref($self);
my $copyrightOwner = $class->copyrightOwner();
my $outputFile = shift;
my $orig_fileString = shift;
my $heading = shift;
if ($class eq "HeaderDoc::Header") {
my $headercopyright = $self->headerCopyrightOwner();
if (!($headercopyright eq "")) {
$copyrightOwner = $headercopyright;
}
}
my $HTMLmeta = "";
if ($class eq "HeaderDoc::Header") {
$HTMLmeta = $self->HTMLmeta();
}
calcDepth($outputFile);
my $fileString = html_fixup_links($self, $orig_fileString);
open(OUTFILE, ">$outputFile") || die "Can't write $outputFile.\n";
if ($^O =~ /MacOS/i) {MacPerl::SetFileInfo('MSIE', 'TEXT', "$outputFile");};
print OUTFILE "\n";
print OUTFILE "";
print OUTFILE $self->styleSheet();
print OUTFILE "\n $heading\n $HTMLmeta \n";
print OUTFILE "\n";
if ($HeaderDoc::insert_header) {
print OUTFILE "\n";
print OUTFILE $self->htmlHeader()."\n";
print OUTFILE "\n";
}
print OUTFILE "$heading
\n";
print OUTFILE $fileString;
print OUTFILE "";
print OUTFILE "
© $copyrightOwner " if (length($copyrightOwner));
# print OUTFILE "(Last Updated $dateStamp)\n";
my $filedate = $self->updated();
if (length($filedate)) {
print OUTFILE "(Last Updated $filedate)\n";
} else {
print OUTFILE "(Last Updated $dateStamp)\n";
}
print OUTFILE "
";
print OUTFILE "\n";
close OUTFILE;
}
sub objGroup { # used for sorting
my $obj1 = $a;
my $obj2 = $b;
return ($obj1->group() cmp $obj2->group());
}
sub objName { # used for sorting
my $obj1 = $a;
my $obj2 = $b;
return ($obj1->name() cmp $obj2->name());
}
sub byLinkage { # used for sorting
my $obj1 = $a;
my $obj2 = $b;
return ($obj1->linkageState() cmp $obj2->linkageState());
}
sub byAccessControl { # used for sorting
my $obj1 = $a;
my $obj2 = $b;
return ($obj1->accessControl() cmp $obj2->accessControl());
}
sub linkageAndObjName { # used for sorting
my $obj1 = $a;
my $obj2 = $b;
my $linkAndName1 = $obj1->linkageState() . $obj1->name();
my $linkAndName2 = $obj2->linkageState() . $obj2->name();
if ($HeaderDoc::sort_entries) {
return ($linkAndName1 cmp $linkAndName2);
} else {
return byLinkage($obj1, $obj2); # (1 cmp 2);
}
}
sub byMethodType { # used for sorting
my $obj1 = $a;
my $obj2 = $b;
if ($HeaderDoc::sort_entries) {
return ($obj1->isInstanceMethod() cmp $obj2->isInstanceMethod());
} else {
return (1 cmp 2);
}
}
##################### Debugging ####################################
sub printObject {
my $self = shift;
print "------------------------------------\n";
print "APIOwner\n";
print "outputDir: $self->{OUTPUTDIR}\n";
print "constantsDir: $self->{CONSTANTSDIR}\n";
print "datatypesDir: $self->{DATATYPESDIR}\n";
print "functionsDir: $self->{FUNCTIONSDIR}\n";
print "methodsDir: $self->{METHODSDIR}\n";
print "typedefsDir: $self->{TYPEDEFSDIR}\n";
print "constants:\n";
&printArray(@{$self->{CONSTANTS}});
print "functions:\n";
&printArray(@{$self->{FUNCTIONS}});
print "methods:\n";
&printArray(@{$self->{METHODS}});
print "typedefs:\n";
&printArray(@{$self->{TYPEDEFS}});
print "structs:\n";
&printArray(@{$self->{STRUCTS}});
print "Inherits from:\n";
$self->SUPER::printObject();
}
sub fixup_links
{
my $self = shift;
my $string = shift;
my $mode = shift;
my $ret = "";
my $localDebug = 0;
my $toplevel = 0;
if ($mode > 1) {
$mode = $mode - 2;
$toplevel = 1;
}
my $linkprefix = "";
my $count = $depth;
while ($count) {
$linkprefix .= "../";
$count--;
}
$linkprefix =~ s/\/$//;
$string =~ s/\@\@docroot/$linkprefix/sg;
my @elements = split(/, $string);
foreach my $element (@elements) {
if ($element =~ /^hd_link (.*?)>/) {
# print "found.\n";
my $oldtarget = $1;
my $newtarget = $oldtarget;
my $prefix = $self->apiUIDPrefix();
if (!($oldtarget =~ /\/\/$prefix/)) {
warn("link needs to be resolved.\n") if ($localDebug);
warn("target is $oldtarget\n") if ($localDebug);
$newtarget = resolveLink($oldtarget);
warn("new target is $newtarget\n") if ($localDebug);
}
# print "element is $element\n";
$element =~ s/^hd_link.*?>\s?//;
# print "link name is $element\n";
if ($mode) {
if ($newtarget =~ /logicalPath=\".*\"/) {
$ret .= "";
} else {
$ret .= "";
}
$ret .= $element;
# $ret .= "";
} else {
# if ($newtarget eq $oldtarget) {
$ret .= "";
$ret .= $element;
# $ret .= "";
# } else {
# if ($toplevel) {
# $ret .= "";
# } else {
# $ret .= "";
# }
# $ret .= $element;
# $ret .= "\n";
# }
}
} else {
if ($element =~ s/^\/hd_link>//) {
if ($mode) {
$ret .= "";
} else {
$ret .= "";
}
$ret .= $element;
} else {
$ret .= "<$element";
}
}
}
$ret =~ s/^/;
return $ret;
}
sub toplevel_html_fixup_links
{
my $self = shift;
my $string = shift;
my $resolver_output = fixup_links($self, $string, 2);
return $resolver_output;
}
sub html_fixup_links
{
my $self = shift;
my $string = shift;
my $resolver_output = fixup_links($self, $string, 0);
return $resolver_output;
}
sub xml_fixup_links
{
my $self = shift;
my $string = shift;
my $resolver_output = fixup_links($self, $string, 1);
return $resolver_output;
}
1;