#! /usr/bin/perl -w # # Class name: APIOwner # Synopsis: Abstract superclass for Header and OO structures # # Last Updated: $Date: 2014/02/25 14:46:13 $ # # 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@ # ###################################################################### # /*! # @header # @abstract # APIOwner class package file. # @discussion # This file contains the APIOwner class, which is # the base class for any API construct that contains functions # or methods (e.g. headers, modules, classes, protocols, # categories, packages, etc.). # # See the class documentation below for more details. # @indexgroup HeaderDoc API Objects # */ # /*! # @abstract # Intermediate API object base class for classes, headers, packages, # namespaces, and so on. # # @discussion # The APIOwner class is the base class for API symbol # types that contain other symbols (not counting constants or fields # in structs, enums, and typedefs). # # This class is a subclass of # {@link //apple_ref/perl/cl/HeaderDoc::HeaderElement HeaderElement}. # # This class is subclassed by # {@link //apple_ref/perl/cl/HeaderDoc::Header Header}, # {@link //apple_ref/perl/cl/HeaderDoc::CPPClass CPPClass} # (classes in all languages except Objective-C), and # {@link //apple_ref/perl/cl/HeaderDoc::ObjCContainer ObjCContainer} # (which is, in turn, subclassed by # {@link //apple_ref/perl/cl/HeaderDoc::ObjCClass ObjCClass}, # {@link //apple_ref/perl/cl/HeaderDoc::ObjCCategory ObjCCategory}, and # {@link //apple_ref/perl/cl/HeaderDoc::ObjCProtocol ObjCProtocol}). # # This API object type should never actually be emitted as output; only # its subclasses are relevant. # # @var ALSOINCLUDE # Contains an array of names of functions to "also include" in # the documentation for this class/pseudoclass. Mainly intended # for applying class-like behavior to procedural languages. # @var APPLEREFUSED # A reference to a hash containing API references that have been # emitted already in the context of this API owner. This is # needed so that it can be reset if a class is re-emitted (after # category folding, for example). # @var CATEGORIES # An array of # {@link //apple_ref/perl/cl/HeaderDoc::ObjCCategory ObjCCategory} # objects within this class or header. # @var CATEGORIESDIR # The directory where output will be written for categories # within this header. Set by {@link outputDir}. # @var CCLASS # Set to 1 for a C pseudoclass, else 0. # @var CLASSES # An array of # {@link //apple_ref/perl/cl/HeaderDoc::CPPClass CPPClass} or # {@link //apple_ref/perl/cl/HeaderDoc::ObjCClass ObjCClass} # objects within this class or header. # @var CLASSESDIR # The directory where output will be written for classes # within this header. Set by {@link outputDir}. # @var CONSTANTSDIR # The directory where output will be written for constants # within this header. Set by {@link outputDir}. # @var CURRENTCLASS # The last class added to this header (or class) object. # See {@link currentClass}. # @var DATATYPESDIR # The directory where output will be written for data types # within this header. Set by {@link outputDir}. # @var ENCODING # The character encoding (guessed) for this header. # @var ENUMS # An array of # {@link //apple_ref/perl/cl/HeaderDoc::Enum Enum} # objects within this class or header. # @var ENUMSDIR # The directory where output will be written for enumerations # within this header. Set by {@link outputDir}. # @var EXPLICITSUPER # Set to 1 if the superclass is specified explicitly with # the \@superclass tag. See {@link explicitSuper}. # @var EXPORTINGFORDB # Deprecated. # @var EXPORTSDIR # The directory where output will be written for database exports # from this header. Set by {@link outputDir}. Unused. # @var FUNCTIONGROUPSTATE # Used during embedded markup processing to keep track of the most # recent \@functiongroup or \@methodgroup # tag value. # @var FUNCTIONS # An array of # {@link //apple_ref/perl/cl/HeaderDoc::Function Function} # objects within this class or header. # @var FUNCTIONSDIR # The directory where output will be written for functions # within this header. Set by {@link outputDir}. # @var GROUPS # An array of # {@link //apple_ref/perl/cl/HeaderDoc::Group Group} # objects within this class or header. # @var HEADEROBJECT # The {@link //apple_ref/perl/cl/HeaderDoc::Header Header} # object for the header that contains this class. (For a # header, this points to itself.) See {@link headerObject}. # @var ISFRAMEWORK # Set to 1 if this object resulted from an \@framework # tag, else 0. # @var ISMERGED # Set to 1 if this the superclass members have been merged # into this class (if applicable), else 0. See {@link isMerged}. # @var ISMODULE # Set to 1 if this class is actually a module in IDL. See {@link isModule}. # @var METHODS # An array of # {@link //apple_ref/perl/cl/HeaderDoc::Method Method} # objects within this class or header. # @var METHODSDIR # The directory where output will be written for methods # within this header. Set by {@link outputDir}. # @var OUTPUTDIR # The output directory for this header. Set by {@link outputDir}. # @var PDEFINES # An array of # {@link //apple_ref/perl/cl/HeaderDoc::PDefine PDefine} # objects within this class or header. # @var PDEFINESDIR # The directory where output will be written for #define # macros within this header. Set by {@link outputDir}. # @var PROPS # An array of # {@link //apple_ref/perl/cl/HeaderDoc::Var Var} property # objects within this class or header. # @var PROPSDIR # The directory where output will be written for properties # within this header. Set by {@link outputDir}. # @var PROTOCOLS # An array of # {@link //apple_ref/perl/cl/HeaderDoc::ObjCProtocol ObjCProtocol} # objects within this class or header. # @var PROTOCOLSDIR # The directory where output will be written for protocols # within this header. Set by {@link outputDir}. # @var STRUCTS # An array of # {@link //apple_ref/perl/cl/HeaderDoc::Struct Struct} # objects within this class or header. # @var STRUCTSDIR # The directory where output will be written for structs # within this header. Set by {@link outputDir}. # @var TOCTITLEPREFIX # The prefix that precedes the name of the header or file # in the left-side table of contents. See {@link tocTitlePrefix}. # @var TYPEDEFS # An array of # {@link //apple_ref/perl/cl/HeaderDoc::Typedef Typedef} # objects within this class or header. # @var TYPEDEFSDIR # The directory where output will be written for typedefs # within this header. Set by {@link outputDir}. # @var UNSORTED # Stores whether the TOC for this API owner object should be # displayed without sorting. Use {@link unsorted} to access # this variable. # @var VARSDIR # The directory where output will be written for variables # within this header. Set by {@link outputDir}. # */ package HeaderDoc::APIOwner; BEGIN { foreach (qw(Mac::Files)) { $MOD_AVAIL{$_} = eval "use $_; 1"; } } use HeaderDoc::HeaderElement; use HeaderDoc::Group; use HeaderDoc::Utilities qw(findRelativePath safeName getAPINameAndDisc printArray printHash resolveLink sanitize dereferenceUIDObject validTag objName byLinkage byAccessControl objGroup linkageAndObjName byMethodType html_fixup_links xml_fixup_links calcDepth); use HeaderDoc::BlockParse qw(blockParseOutside); use File::Basename; use Cwd; use Carp qw(cluck); use strict; use vars qw(@ISA); # /*! # @abstract # The revision control revision number for this module. # @discussion # In the git repository, contains the number of seconds since # January 1, 1970. # */ $HeaderDoc::APIOwner::VERSION = '$Revision: 1393368373 $'; my $addToDebug = 0; # Inheritance @ISA = qw(HeaderDoc::HeaderElement); ################ Portability ################################### my $isMacOS; my $pathSeparator; if ($^O =~ /MacOS/io) { $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, "UTF-8"); ###################################################################### # class variables and accessors { my $_copyrightOwner; my $_defaultFrameName; my $_compositePageName; my $_htmlHeader; my $_htmlFooter; my $_apiUIDPrefix; # my $_headerObject; # /*! @abstract # Gets/sets the copyright owner for the header, # specified by the \@copyright field. # @param class # The APIOwner class object. # @param _copyrightOwner # The new owner. (Optional) # */ sub copyrightOwner { my $class = shift; if (@_) { $_copyrightOwner = shift; } return $_copyrightOwner; } # /*! @abstract # Gets/sets the value of the defaultFrameName # field in the HeaderDoc config file. # @param class # The APIOwner class object. # @param _defaultFrameName # The new filename. (Optional) # */ sub defaultFrameName { my $class = shift; if (@_) { $_defaultFrameName = shift; } return $_defaultFrameName; } # /*! # @abstract # Gets/sets the filename that should be used for the composite page. # # @discussion # In the default mode (iframe output), this returns the default # frame name. # # This returns the value of the compositePageName # field in the HeaderDoc config file if iframe output # is disabled. # @param class # The APIOwner class object. # @param _compositePageName # The new filename. (Optional) # */ sub compositePageName { my $class = shift; if (@_) { $_compositePageName = shift; } if ($HeaderDoc::use_iframes) { return $class->defaultFrameName(); # index.html } return $_compositePageName; } # /*! @abstract # Gets/sets the value of the htmlHeader # field in the HeaderDoc config file. # @param self # The APIOwner class object. # @param _htmlHeader # The new HTML header bits. (Optional) # */ sub htmlHeader { my $self = shift; if (@_) { $_htmlHeader = shift; $_htmlHeader =~ s/{\@docroot}/\@\@docroot/sg; } if ($self eq "HeaderDoc::APIOwner") { return $_htmlHeader; } if ($self->outputformat eq "hdxml") { return xml_fixup_links($self, $_htmlHeader); } else { return html_fixup_links($self, $_htmlHeader); } } # /*! @abstract # Gets/sets the value of the htmlFooter # field in the HeaderDoc config file. # @param self # The APIOwner class object. # @param _htmlFooter # The new HTML footer bits. (Optional) # */ sub htmlFooter { my $self = shift; if (@_) { $_htmlFooter = shift; $_htmlFooter =~ s/{\@docroot}/\@\@docroot/sg; } if ($self eq "HeaderDoc::APIOwner") { return $_htmlFooter; } if ($self->outputformat eq "hdxml") { return xml_fixup_links($self, $_htmlFooter); } else { return html_fixup_links($self, $_htmlFooter); } } # /*! @abstract # Gets/sets the value of the apiUIDPrefix # field in the HeaderDoc config file. # @param class # The APIOwner class object. # @param _apiUIDPrefix # The new prefix. (Optional) # */ sub apiUIDPrefix { my $class = shift; if (@_) { $_apiUIDPrefix = shift; } return $_apiUIDPrefix; } } # /*! # @abstract # Gets/sets the header containing a class, category, protocol, etc. # @discussion # Returns a reference to the header associated with a class, category, protocol, # or other API-owning structure. For a header, returns a reference to itself. # @param class # The APIOwner class object. # @param headerObject # The new object. (Optional) # */ sub headerObject { my $class = shift; if (@_) { $class->{HEADEROBJECT} = shift; } return $class->{HEADEROBJECT}; } # /*! # @abstract # Updates the dateStamp global variable. # */ sub fix_date($) { my $encoding = shift; $dateStamp = HeaderDoc::HeaderElement::strdate($moy, $dom, $year, $encoding); # print STDERR "fixed date stamp.\n"; return $dateStamp; } # /*! # @abstract # Initializes an instance of an APIOwner object. # @param self # The object to initialize. # */ 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->{PROPSDIR} = 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; # $self->{ENCODING} = undef; $self->{CLASS} = "HeaderDoc::APIOwner"; my %groups = (); $self->{GROUPS} = \%groups; } # /*! # @abstract # Duplicates this APIOwner object into another one. # @param self # The object to clone. # @param clone # The victim object. # */ sub clone { my $self = shift; my $clone = undef; if (@_) { $clone = shift; } else { $clone = HeaderDoc::APIOwner->new("LANG" => $self->{LANG}, "SUBLANG" => $self->{SUBLANG}); } $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->{PROPSDIR} = $self->{PROPSDIR}; $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->{ENCODING} = $self->{ENCODING}; $clone->{HEADEROBJECT} = $self->{HEADEROBJECT} = 0; return $clone; } # /*! @abstract # Indicates whether the class is a C pseudoclass. # @param self # The APIOwner object. # */ sub CClass { my $self = shift; if (@_) { $self->{CCLASS} = shift; } return $self->{CCLASS}; } # /*! # @abstract # Returns the class type for the block parser. # @discussion # Returns the class type in a form that the block parser # needs when handling the enclosed elements. # @param self # The APIOwner object. # */ sub classType { my $self = shift; my $type = $self->{CLASS}; if ($type =~ /CPPClass/) { if ($self->CClass()) { return "C"; } return $self->sublang(); } elsif ($type =~ /ObjCProtocol/) { return "intf"; } elsif ($type =~ /ObjCCategory/) { return "occCat"; } elsif ($type =~ /ObjCClass/) { return "occ"; } else { warn "Couldn't determine my own class type....\n"; } } # /*! # @abstract # Returns whether the class is a COM interface. # @discussion # Returns 1 if the class is a COM interface (a C pseudoclass # marked with the \@interface tag). Overridden in the CPPClass # class. # @param self # The APIOwner object. # */ sub isCOMInterface { return 0; } # /*! # @abstract # Returns whether an object is an APIOwner (or subclass thereof). # @discussion # Overrides the isAPIOwner method in the HeaderElement class. # @param self # The APIOwner object. # */ sub isAPIOwner { return 1; } # /*! # @abstract # Get/set whether superclass was specified in comment # @discussion # If the superclass is explicitly specified in the markup # with an \@superclass tag, it means that the user wants # to include the functions, data types, etc. from the # superclass in the subclass's documentation where possible. # @param self # The APIOwner object. # @param value # The value to set. (Optional) # */ sub explicitSuper { my $self = shift; if (@_) { my $value = shift; $self->{EXPLICITSUPER} = $value; } return $self->{EXPLICITSUPER}; } # /*! # @abstract # Get/set whether this class has had its superclass's members # merged in yet (if applicable) # @param self # The APIOwner object. # */ sub isMerged { my $self = shift; if (@_) { my $value = shift; $self->{ISMERGED} = $value; } return $self->{ISMERGED}; } # /*! # @abstract # Get/set whether this file contains framework documentation # @discussion # This function returns true if the APIOwner object is a # Header object and the underlying file is a .hdoc file # containing an \@framework tag. # @param self # The APIOwner object. # @param value # The value to set. (Optional) # */ sub isFramework { my $self = shift; if (@_) { my $value = shift; $self->{ISFRAMEWORK} = $value; } return $self->{ISFRAMEWORK}; } # /*! # @abstract # Gets/sets whether this class is a real class or a module # @param self # The APIOwner object. # @param value # The value to set. (Optional) # */ sub isModule { my $self = shift; if (@_) { my $value = shift; $self->{ISMODULE} = $value; $self->noRegisterUID($value); } return $self->{ISMODULE}; } # /*! # @abstract # Gets/sets the array of classes within this header (or # enclosing class). # @param self # The APIOwner object. # @param CLASSES # The array value to set. (Optional) # */ sub classes { my $self = shift; if (@_) { @{ $self->{CLASSES} } = @_; } ($self->{CLASSES}) ? return @{ $self->{CLASSES} } : return (); } # /*! # @abstract # Returns whether the header contains a class with a given name. # @discussion # Used by the BlockParse code to check to see if a header contains # a particular class. This is so that C++ methods outside the # class braces (in a .cpp file) can be merged into the class. # # This could probably be replaced by a global symbol lookup for # the class object now. # @param name # The class name to look for. # */ sub findClass { my $self = shift; my $name = shift; foreach my $class (@{ $self->{CLASSES} }) { if ($class->name() eq $name) { return $class; } } return undef; } # /*! @abstract # Gets/sets the path to the directory where protocol output should be written. # @discussion # This always contains [output_directory]/[this_header_directory]/Protocols. # @param self # The APIOwner object. # @param CLASSES # The value to set. (Optional) # */ sub protocolsDir { my $self = shift; if (@_) { $self->{PROTOCOLSDIR} = shift; } return $self->{PROTOCOLSDIR}; } # /*! @abstract # Gets/sets the array of protocols that are enclosed in this header. # @param self # The APIOwner object. # @param CLASSES # The array value to set. (Optional) # */ sub protocols { my $self = shift; if (@_) { @{ $self->{PROTOCOLS} } = @_; } ($self->{PROTOCOLS}) ? return @{ $self->{PROTOCOLS} } : return (); } # /*! @abstract # Adds a protocol associated with this header. # @param self # The APIOwner object. # @param CLASSES # The {@link //apple_ref/perl/cl/HeaderDoc::ObjCProtocol HeaderDoc::ObjCProtocol} # objects to add. # */ sub addToProtocols { my $self = shift; if (@_) { foreach my $item (@_) { if ($addToDebug) { print STDERR "ADDED $item TO PROTOCOLS\n"; } if (!$item->{INSERTED}) { $item->{INSERTED} = 42; } push (@{ $self->{PROTOCOLS} }, $item); } } return @{ $self->{PROTOCOLS} }; } # /*! @abstract # Gets/sets the path to the directory where category output should be written. # @discussion # This always contains [output_directory]/[this_header_directory]/Categories. # @param self # The APIOwner object. # @param CLASSES # The value to set. (Optional) # */ sub categoriesDir { my $self = shift; if (@_) { $self->{CATEGORIESDIR} = shift; } return $self->{CATEGORIESDIR}; } # /*! @abstract # Gets/sets the array of categories that are enclosed in this header. # @param self # The APIOwner object. # @param CLASSES # The array value to set. (Optional) # */ sub categories { my $self = shift; if (@_) { @{ $self->{CATEGORIES} } = @_; } ($self->{CATEGORIES}) ? return @{ $self->{CATEGORIES} } : return (); } # /*! @abstract # Adds a category associated with this header. # @param self # The APIOwner object. # @param CLASSES # The {@link //apple_ref/perl/cl/HeaderDoc::ObjCCategory HeaderDoc::ObjCCategory} objects to add. # */ sub addToCategories { my $self = shift; if (@_) { foreach my $item (@_) { if ($addToDebug) { print STDERR "ADDED $item TO CATEGORIES\n"; } if (!$item->{INSERTED}) { $item->{INSERTED} = 42; } push (@{ $self->{CATEGORIES} }, $item); } } return @{ $self->{CATEGORIES} }; } # /*! # @abstract # Removes a maximum of one category per invocation. # @discussion # A category gets removed if the higher level code successfully finds # the associated class and adds the category methods to it. # @param self # The APIOwner object. # @param CLASSES # The category to remove. (Optional) # */ sub removeFromCategories { my $self = shift; my $objToRemove = shift; my $nameOfObjToRemove = $objToRemove->name(); my @tempArray; my @categories = $self->categories(); my $localDebug = 0; if (!@categories) {return;}; foreach my $obj (@categories) { if (ref($obj) eq "HeaderDoc::ObjCCategory") { my $fullName = $obj->name(); if ($fullName ne $nameOfObjToRemove) { push (@tempArray, $obj); } else { print STDERR "Removing $fullName from Header object.\n" if ($localDebug); } } } # we set it directly since the accessor will not allow us to set an empty array @{ $self->{CATEGORIES} } = @tempArray; } ### # /*! ### # @abstract ### Returns protocols within this header ### # */ ### sub protocols ### { ### return (); ### } ### ### # /*! ### # @abstract ### # Returns categories within this header ### # */ ### sub categories ### { ### return (); ### } # /*! # @abstract # Adds a class to class list # @discussion # Both headers and classes can contain classes (in # some languages). This function is used for both cases. # @param self # The APIOwner object. # @param CLASSES # The {@link //apple_ref/perl/cl/HeaderDoc::CPPClass HeaderDoc::CPPClass} objects to add. # */ sub addToClasses { my $self = shift; if (@_) { foreach my $item (@_) { # print STDERR "FOR OBJECT $self, ADDING TO CLASSES: $item\n"; # print STDERR "ref(\$item): ".ref($item)."\n"; if ($addToDebug) { print STDERR "ADDED $item TO CLASSES\n"; } $self->currentClass($item); if (!$item->{INSERTED}) { $item->{INSERTED} = 42; } push (@{ $self->{CLASSES} }, $item); } } return @{ $self->{CLASSES} }; } # /*! @abstract # Gets/sets the last class added to this header (or class) object. # @param self # The APIOwner object. # @param class # The array value to set. (Optional) # @discussion # Used for debugging purposes when dbprint() is called on # the header object during processing. # */ sub currentClass { my $self = shift; if (@_) { @{ $self->{CURRENTCLASS} } = @_; } return @{ $self->{CURRENTCLASS} }; } # /*! @abstract # Gets/sets the current output directory. # @discussion # This function returns the output directory (usually specified # by -o on the command line). # @param self # The APIOwner object. # @param directory # The new default output directory. (Optional) # */ sub outputDir { my $self = shift; if (@_) { my $rootOutputDir = shift; if (!$self->use_stdout() && !$HeaderDoc::running_test) { 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 (in APIOwner). 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->propsDir("$rootOutputDir$pathSeparator"."Properties"); $self->pDefinesDir("$rootOutputDir$pathSeparator"."PDefines"); $self->enumsDir("$rootOutputDir$pathSeparator"."Enums"); $self->classesDir("$rootOutputDir$pathSeparator"."Classes"); $self->classesDir("$rootOutputDir$pathSeparator"."Classes"); $self->protocolsDir("$rootOutputDir$pathSeparator"."Protocols"); $self->categoriesDir("$rootOutputDir$pathSeparator"."Categories"); } return $self->{OUTPUTDIR}; } # /*! # @abstract # Gets/sets the prefix for the title line in the left-side TOC. # @discussion # Returns Header:, Class:, etc. (with a # trailing space), depending on the type of object it is called on. # This string is emitted before the name of the header, class, etc. # in the table of contents (left column). # # This value is set by the _initialize routine in # each subclass. # @param self # The APIOwner object. # @param directory # The value to set. (Optional) # */ sub tocTitlePrefix { my $self = shift; if (@_) { $self->{TOCTITLEPREFIX} = shift; } return $self->{TOCTITLEPREFIX}; } # /*! @abstract # Gets/sets the path to the directory where constant output should be written. # @discussion # This always contains [output_directory]/[this_header_directory]/Constants. # @param self # The APIOwner object. # @param CLASSES # The value to set. (Optional) # */ sub constantsDir { my $self = shift; if (@_) { $self->{CONSTANTSDIR} = shift; } return $self->{CONSTANTSDIR}; } # /*! @abstract # Gets/sets the path to the directory where data type output should be written. # @discussion # This always contains [output_directory]/[this_header_directory]/DataTypes. # @param self # The APIOwner object. # @param CLASSES # The value to set. (Optional) # */ sub datatypesDir { my $self = shift; if (@_) { $self->{DATATYPESDIR} = shift; } return $self->{DATATYPESDIR}; } # /*! @abstract # Gets/sets the path to the directory where struct output should be written. # @discussion # This always contains [output_directory]/[this_header_directory]/Structs. # @param self # The APIOwner object. # @param CLASSES # The value to set. (Optional) # */ sub structsDir { my $self = shift; if (@_) { $self->{STRUCTSDIR} = shift; } return $self->{STRUCTSDIR}; } # /*! @abstract # Gets/sets the path to the directory where variable output should be written. # @discussion # This always contains [output_directory]/[this_header_directory]/Vars. # @param self # The APIOwner object. # @param CLASSES # The value to set. (Optional) # */ sub varsDir { my $self = shift; if (@_) { $self->{VARSDIR} = shift; } return $self->{VARSDIR}; } # /*! @abstract # Gets/sets the path to the directory where property output should be written. # @discussion # This always contains [output_directory]/[this_header_directory]/Properties. # @param self # The APIOwner object. # @param CLASSES # The value to set. (Optional) # */ sub propsDir { my $self = shift; if (@_) { $self->{PROPSDIR} = shift; } return $self->{PROPSDIR}; } # /*! @abstract # Gets/sets the path to the directory where #define # output should be written. # @discussion # This always contains [output_directory]/[this_header_directory]/PDefines. # @param self # The APIOwner object. # @param CLASSES # The value to set. (Optional) # */ sub pDefinesDir { my $self = shift; if (@_) { $self->{PDEFINESDIR} = shift; } return $self->{PDEFINESDIR}; } # /*! @abstract # Gets/sets the path to the directory where class output should be written. # @discussion # This always contains [output_directory]/[this_header_directory]/Classes. # @param self # The APIOwner object. # @param CLASSESDIR # The value to set. (Optional) # */ sub classesDir { my $self = shift; if (@_) { $self->{CLASSESDIR} = shift; } return $self->{CLASSESDIR}; } # /*! @abstract # Gets/sets the path to the directory where enum output should be written. # @discussion # This always contains [output_directory]/[this_header_directory]/Enums. # @param self # The APIOwner object. # @param ENUMSDIR # The value to set. (Optional) # */ sub enumsDir { my $self = shift; if (@_) { $self->{ENUMSDIR} = shift; } return $self->{ENUMSDIR}; } # /*! @abstract # Gets/sets the path to the directory where function output should be written. # @discussion # This always contains [output_directory]/[this_header_directory]/Functions. # @param self # The APIOwner object. # @param FUNCTIONSDIR # The value to set. (Optional) # */ sub functionsDir { my $self = shift; if (@_) { $self->{FUNCTIONSDIR} = shift; } return $self->{FUNCTIONSDIR}; } # /*! @abstract # Gets/sets the path to the directory where method output should be written. # @discussion # This always contains [output_directory]/[this_header_directory]/Methods. # @param self # The APIOwner object. # @param METHODSDIR # The value to set. (Optional) # */ sub methodsDir { my $self = shift; if (@_) { $self->{METHODSDIR} = shift; } return $self->{METHODSDIR}; } # /*! # @abstract # Private function for an Apple-specific output format. # @discussion # Converts an array into JSON notation. # @param optional_bits # A reference to the array to emit. # */ sub arrayToJSON { my $optional_bits = shift; my @bits = @{$optional_bits}; my $retstring = ""; foreach my $bit (@bits) { my $class = ref($bit) || $bit; if ($class =~ /HASH/) { $retstring .= "{\n".keysToJSON($bit)."},\n"; } else { $retstring .= "\"$bit\",\n"; } } $retstring =~ s/,\n$//s; return $retstring; } # /*! # @abstract # Private function for an Apple-specific output format. # @discussion # Converts a key in an associative array into a JSON key. # When you call this, the surrounding JSON array should # already be open. # @param optional_bits # A reference to an array full of keys to emit. # */ sub keysToJSON { my $optional_bits = shift; my %bits = %{$optional_bits}; my $retstring = ""; foreach my $key (keys %bits) { my $val = $bits{$key}; my $class = ref($val) || $val; # print "CLASS: $class\n"; if ($val eq "false") { $retstring .= "\"$key\":false,\n"; } elsif ($val eq "true") { $retstring .= "\"$key\":true,\n"; } elsif ($class =~ /ARRAY/) { $retstring .= "\"$key\": [\n".arrayToJSON($val)."\n],\n"; } elsif ($class =~ /HASH/) { $retstring .= "\"$key\": {\n".keysToJSON($val)."\n},\n"; } else { $retstring .= "\"$key\":\"$val\",\n"; } } $retstring =~ s/,\n$//s; return $retstring; } # /*! # @abstract # Private function for an Apple-specific output format. # @discussion # Generates a JSON-style table of contents. # @param href # The section or book link href. # @param title # The section or book title. # @param mode # Mode value. 0 means open and close with no contents. # 1 means open and leave open. 2 means close and add a # trailing comma. 3 means close without trailing comma. # @param pos # Value for the closedAt key. Useful for debugging # this code. # @param optional_bits # Additional keys to add at the top level of the TOC. # */ sub tocJSON { my $href = shift; my $title = shift; my $mode = shift; my $pos = shift; my $optional_bits = shift; $title =~ s/[\n\r]+/ /sg; my $retstring = ""; my $debugMode = 1; if ($title eq "") { $title = "[Uncategorized]"; } # cluck("MODE: $mode HREF $href TITLE $title\n"); my $aref = $href; if ($aref =~ /#\/\//) { $aref =~ s/^.*#//s; } else { $aref = ""; } if ($mode == 2 || $mode == 3) { # Close contents. my $comma = ","; if ($mode == 3) { $comma = ""; } $retstring .= "]\n"; $retstring .= ",\"closedAt\":\"$pos\"\n" if ($debugMode); $retstring .= "}$comma\n"; } if ($mode == 0 || $mode == 1) { # Open it. $retstring .= "{\n"; $retstring .= "\"insertedAt\":\"$pos\",\n" if ($debugMode); $retstring .= "\"href\":\"$href\",\n"; $retstring .= "\"aref\":\"$aref\",\n"; $retstring .= "\"title\":\"".striptitle($title)."\",\n"; if ($optional_bits) { $retstring .= keysToJSON($optional_bits).",\n"; } $retstring .= "\"sections\": [\n"; } if ($mode == 0) { # Close it. $retstring .= tocJSON($href, $title, 2, $pos, undef); } return $retstring; } # /*! # @abstract # Returns the left-side TOC for the Classes box. # @discussion # This generates everything under the Classes section of the left-side # TOC. # # This is similar to {@link tocStringSub} except that the actual URLs are # generated differently because of the HTML structure being linked to. # */ sub tocStringSubForClasses { 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 $tag = shift; my $newTOC = shift; if (!($self->langSupportsAccess())) { $ignore_access = 1; } my $localDebug = 0; my $class = ref($self) || $self; my @groups = @{$groupref}; my @objs = @{$objref}; my $tocString = ""; my $jumpLabel = ""; if ($tag && $tag ne "") { $jumpLabel = "#HeaderDoc_$tag"; } my $firstgroup = 1; my $preface = "  "; my $entrypreface = "      "; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @objs; } else { @tempobjs = @objs; } foreach my $obj (@tempobjs) { if ($obj->isInternal() && !$HeaderDoc::document_internal) { next; } my $name = $obj->name(); my $urlname = $obj->apiuid(); # sanitize($name); my $safename = &safeName(filename => $name); my $class_baseref = $baseref; $class_baseref =~ s/{}/\Q$safename\E/g; if ($self->outputformat eq "hdxml") { $tocString .= "XMLFIX$entrypreface$name
\n"; } elsif ($self->outputformat eq "html") { if ($newTOC == 3) { $tocString .= tocJSON("$class_baseref#$urlname", $name, 0, "tocStringSubForClasses", undef); } elsif ($newTOC) { $tocString .= tocSubEntry("$class_baseref#$urlname", "doc", $name); } elsif ($HeaderDoc::use_iframes) { $tocString .= "$entrypreface$name
\n"; } else { $tocString .= "$entrypreface$name
\n"; } } else { } } # return $tocString; return tocWrapSubEntries("".$tocString); } # /*! # @abstract # Returns the left-side TOC HTML for a set of data types, functions, methods, etc. # @discussion # This function takes an array of objects and generates the left-side TOC entries for those # objects wrapped in appropriate HTML structures. # # This is similar to {@link tocStringSubForClasses} except that # the actual URL is generated differently because of the HTML structure. # */ 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 $tag = shift; my $newTOC = shift; if (!($self->langSupportsAccess())) { $ignore_access = 1; } my $localDebug = 0; my $class = ref($self) || $self; my @groups = @{$groupref}; my @objs = @{$objref}; my $tocString = ""; my $jumpLabel = ""; if ($tag && $tag ne "") { $jumpLabel = "#HeaderDoc_$tag"; } my $tempurl = ""; if ($composite) { $tempurl = "$compositePageName$jumpLabel"; } else { $tempurl = "$baseref$jumpLabel"; } if ($newTOC) { $tocString .= $self->tocHeading($tempurl, $head, "doc"); } elsif ($HeaderDoc::use_iframes) { $tocString .= "

$head

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

$head

\n"; } my $firstgroup = 1; foreach my $group (@groups) { my $firstaccess = 1; my $done_one = 0; print STDERR "Sorting group $group\n" if ($localDebug); my @groupobjs = (); my @tempobjs = (); my @cdobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @objs; } else { @tempobjs = @objs; } foreach my $obj (@tempobjs) { if ($obj->isInternal() && !$HeaderDoc::document_internal) { next; } if ($obj->group() eq $group) { $done_one = 1; if (!!$self->unsorted() || !$obj->constructor_or_destructor()) { push(@groupobjs, $obj); } else { push(@cdobjs, $obj); } } } if (!$done_one) { # empty group next; } my $preface = "  "; my $entrypreface = "      "; # if ($done_one) { $tocString .= " 
" } if (!length($group) && ($newTOC != 3)) { # $entrypreface = $preface; } else { if ($newTOC) { $tocString .= tocGroup($group, $firstgroup); } else { $tocString .= "$preface$group:
"; } } my @Cs; my @publics; my @protecteds; my @privates; if (!$self->unsorted()) { @tempobjs = sort byAccessControl @groupobjs; } else { @tempobjs = @groupobjs; } foreach my $obj (@tempobjs) { if ($obj->isInternal() && !$HeaderDoc::document_internal) { next; } my $access = $obj->accessControl(); $firstgroup = 0; # print STDERR "ACCESS: $access\n"; if ($access =~ /public/o || $ignore_access){ push (@publics, $obj); } elsif ($access =~ /protected/o){ push (@protecteds, $obj); } elsif ($access =~ /private/o){ push (@privates, $obj); } elsif ($access eq "") { push (@Cs, $obj); } else { # assume public (e.g. C) push (@publics, $obj); } } if (@cdobjs) { $tocString .= "\n"; my $tocStringLocal = ""; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @cdobjs; } else { @tempobjs = @cdobjs; } foreach my $obj (@tempobjs) { my $name = $obj->name(); my $urlname = $obj->apiuid(); # sanitize($name); if ($self->outputformat eq "hdxml") { $tocStringLocal .= "XMLFIX$entrypreface$name
\n"; } elsif ($self->outputformat eq "html") { if ($newTOC) { $tocStringLocal .= tocSubEntry("$baseref#$urlname", "doc", $name); } elsif ($HeaderDoc::use_iframes) { $tocStringLocal .= "$entrypreface$name
\n"; } else { $tocStringLocal .= "$entrypreface$name
\n"; } } else { } } $tocString .= tocWrapSubEntries("".$tocStringLocal); } if (@Cs) { $tocString .= "\n"; my $tocStringLocal = ""; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @Cs; } else { @tempobjs = @Cs; } foreach my $obj (@tempobjs) { my $name = $obj->name(); my $urlname = $obj->apiuid(); # sanitize($name); if ($self->outputformat eq "hdxml") { $tocStringLocal .= "XMLFIX$entrypreface$name
\n"; } elsif ($self->outputformat eq "html") { if ($newTOC) { $tocStringLocal .= tocSubEntry("$baseref#$urlname", "doc", $name); } elsif ($HeaderDoc::use_iframes) { $tocStringLocal .= "$entrypreface$name
\n"; } else { $tocStringLocal .= "$entrypreface$name
\n"; } } else { } } $tocString .= tocWrapSubEntries("".$tocStringLocal); } if (@publics) { if ($class eq "HeaderDoc::Header" || $ignore_access) { if ($newTOC != 3) { $tocString .= "\n"; } } elsif ($self->outputformat eq "hdxml") { $tocString .= "XMLFIX
Public
\n"; } elsif ($self->outputformat eq "html") { if ($newTOC) { $tocString .= $self->tocAccess("Public", $firstaccess); } else { $tocString .= "
Public
\n"; } } else { } $firstaccess = 0; my $tocStringLocal = ""; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @publics; } else { @tempobjs = @publics; } foreach my $obj (@tempobjs) { my $name = $obj->name(); my $urlname = $obj->apiuid(); # sanitize($name); # if ($urlname eq "") { # cluck("Empty urlname! Object was $obj\n"); # } if ($self->outputformat eq "hdxml") { $tocStringLocal .= "XMLFIX$entrypreface$name
\n"; } elsif ($self->outputformat eq "html") { if ($newTOC) { $tocStringLocal .= tocSubEntry("$baseref#$urlname", "doc", $name); } elsif ($HeaderDoc::use_iframes) { $tocStringLocal .= "$entrypreface$name
\n"; } else { $tocStringLocal .= "$entrypreface$name
\n"; } } else { } } $tocString .= tocWrapSubEntries("".$tocStringLocal); if ($newTOC) { if (!($class eq "HeaderDoc::Header" || $ignore_access)) { $tocString .= $self->tocAccessEnd(); } } } if (@protecteds) { my $tocStringLocal = ""; if ($class eq "HeaderDoc::Header" || $ignore_access) { $tocString .= "\n"; } elsif ($self->outputformat eq "hdxml") { $tocString .= "XMLFIX
Protected
\n"; } elsif ($self->outputformat eq "html") { if ($newTOC) { $tocString .= $self->tocAccess("Protected", $firstaccess); } else { $tocString .= "
Protected
\n"; } } else { } $firstaccess = 0; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @protecteds; } else { @tempobjs = @protecteds; } foreach my $obj (@tempobjs) { my $name = $obj->name(); my $urlname = $obj->apiuid(); # sanitize($name); if ($self->outputformat eq "hdxml") { $tocStringLocal .= "XMLFIX$entrypreface$name
\n"; } elsif ($self->outputformat eq "html") { if ($newTOC) { $tocStringLocal .= tocSubEntry("$baseref#$urlname", "doc", $name); } elsif ($HeaderDoc::use_iframes) { $tocStringLocal .= "$entrypreface$name
\n"; } else { $tocStringLocal .= "$entrypreface$name
\n"; } } else { } } $tocString .= tocWrapSubEntries("".$tocStringLocal); if ($newTOC) { $tocString .= $self->tocAccessEnd(); } } if (@privates) { if ($class eq "HeaderDoc::Header" || $ignore_access) { $tocString .= "\n"; } elsif ($self->outputformat eq "hdxml") { $tocString .= "XMLFIX
Private
\n"; } elsif ($self->outputformat eq "html") { if ($newTOC) { $tocString .= $self->tocAccess("Protected", $firstaccess); } else { $tocString .= "
Private
\n"; } } else { } $firstaccess = 0; my $tocStringLocal = ""; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @privates; } else { @tempobjs = @privates; } foreach my $obj (@tempobjs) { my $name = $obj->name(); my $urlname = $obj->apiuid(); # sanitize($name); if ($self->outputformat eq "hdxml") { $tocStringLocal .= "XMLFIX$entrypreface$name
\n"; } elsif ($self->outputformat eq "html") { if ($newTOC) { $tocStringLocal .= tocSubEntry("$baseref#$urlname", "doc", $name); } elsif ($HeaderDoc::use_iframes) { $tocStringLocal .= "$entrypreface$name
\n"; } else { $tocStringLocal .= "$entrypreface$name
\n"; } } else { } } $tocString .= tocWrapSubEntries("".$tocStringLocal); if ($newTOC) { $tocString .= $self->tocAccessEnd(); } } # if (!($group eq "")) { # $tocString .= "

\n"; # } $tocString .= $self->tocGroupEnd(); } if ($newTOC) { $tocString .= $self->tocHeadingEnd(); } return $tocString; } # /*! @abstract # Checks for $name in $array referenced by $arrayref. # @param name # The name to search for. # @param arrayref # A reference to the array to search in. # */ sub inarray { my $name = shift; my $arrayref = shift; my @array = @{$arrayref}; foreach my $arrname (@array) { if ($name eq $arrname) { return 1; } } return 0; } # /*! @abstract # Generates the HTML for the left-side TOC. # @param newTOC # Specifies Apple-style TOC (requires external JavaScript and CSS bits). # @param arrayref # A reference to the array to search in. # */ sub tocString { my $self = shift; my $newTOC = shift; if ($self->outputformat() eq "functions") { return ""; } my $contentFrameName = $self->filename(); my @classes = $self->classes(); my @protocols = $self->protocols(); my @categories = $self->categories(); my $class = ref($self) || $self; $contentFrameName =~ s/(.*)\.h/$1/o; $contentFrameName = &safeName(filename => $contentFrameName); $contentFrameName = $contentFrameName . ".html"; my $composite = $HeaderDoc::ClassAsComposite; my $compositePageName = HeaderDoc::APIOwner->compositePageName(); my $defaultFrameName = HeaderDoc::APIOwner->defaultFrameName(); 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 @ALLpDefines = $self->pDefines(); my @vars = $self->vars(); my $tocString = ""; my @properties = $self->props(); my $baseref = $contentFrameName; if ($composite) { $baseref = $compositePageName; } $tocString .= "\n"; if ($newTOC) { # $tocString .= "


".$HeaderDoc::introductionName."

\n"; $tocString .= $self->tocEntry("$baseref#top", $HeaderDoc::introductionName); } elsif ($HeaderDoc::use_iframes) { $tocString .= "


".$HeaderDoc::introductionName."

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


".$HeaderDoc::introductionName."

\n"; } my @groups = (""); my $localDebug = 0; my @pDefines = (); foreach my $define (@ALLpDefines) { if ($define->isInternal() && !$HeaderDoc::document_internal) { next; } if (!$define->parseOnly()) { push(@pDefines, $define); } } my @objs = ( @funcs, @methods, @constants, @typedefs, @structs, @enums, @pDefines, @vars, @properties ); if (!$self->unsorted()) { @objs = sort objGroup @objs; } foreach my $obj (@objs) { $obj->apirefSetup(); # Perl ivars haven't been set up yet. if ($obj->isInternal() && !$HeaderDoc::document_internal) { next; } # warn "obj is $obj\n"; my $group = $obj->group(); if (!inarray($group, \@groups)) { push (@groups, $group); if ($localDebug) { print STDERR "Added $group\n"; print STDERR "List is:"; foreach my $printgroup (@groups) { print STDERR " $printgroup"; } print STDERR "\n"; } } } # output list of functions as TOC if (@funcs) { my $funchead = "Functions"; if ($class ne "HeaderDoc::Header") { $funchead = "Member Functions"; } my $baseref = "Functions/Functions.html"; if ($composite) { $baseref = $compositePageName; } $tocString .= $self->tocStringSub($funchead, \@groups, \@funcs, $compositePageName, $baseref, $composite, 0, "functions", $newTOC); } if (@methods) { # $tocString .= "

Methods

\n"; my $baseref = "Methods/Methods.html"; if ($composite) { $baseref = $compositePageName; } if ($newTOC) { $tocString .= $self->tocHeading("$baseref#HeaderDoc_methods", "Methods", "doc"); } elsif ($HeaderDoc::use_iframes) { $tocString .= "

Methods

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

Methods

\n"; } my $firstgroup = 1; foreach my $group (@groups) { my $done_one = 0; my $firstaccess = 1; print STDERR "Sorting group $group\n" if ($localDebug); my @groupmeths = (); my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @methods; } else { @tempobjs = @methods; } foreach my $obj (@tempobjs) { if ($obj->isInternal() && !$HeaderDoc::document_internal) { next; } if ($obj->group() eq $group) { $done_one = 1; push(@groupmeths, $obj); } } if (!$done_one) { # empty group next; } if ($newTOC == 3 || (!($group eq ""))) { # if ($done_one) { $tocString .= " 
" } if ($newTOC) { $tocString .= tocGroup($group, $firstgroup); } else { $tocString .= "
  $group:
"; } } my @classMethods; my @instanceMethods; foreach my $obj (sort byMethodType @groupmeths) { if ($obj->isInternal() && !$HeaderDoc::document_internal) { next; } my $type = $obj->isInstanceMethod(); $firstgroup = 0; if ($type =~ /NO/o){ push (@classMethods, $obj); } elsif ($type =~ /YES/o){ push (@instanceMethods, $obj); } else { # assume instanceMethod push (@instanceMethods, $obj); } } if (@classMethods) { if ($class eq "HeaderDoc::Header") { $tocString .= "\n"; } elsif ($self->outputformat eq "html") { if ($newTOC) { $tocString .= $self->tocAccess("Class Methods", $firstaccess); } else { $tocString .= "
Class Methods
\n"; } } else { } $firstaccess = 0; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @classMethods; } else { @tempobjs = @classMethods; } my $tocStringLocal = ""; foreach my $obj (@tempobjs) { my $name = $obj->name(); my $urlname = $obj->apiuid(); if (length($name) > 30) { $name =~ s/:/:\‍/g; } if ($newTOC) { $tocStringLocal .= tocSubEntry("$baseref#$urlname", "doc", $name); } elsif ($HeaderDoc::use_iframes) { $tocStringLocal .= "      +$name
\n"; } else { $tocStringLocal .= "      +$name
\n"; } } if ($newTOC) { $tocString .= $self->tocAccessEnd(); } $tocString .= tocWrapSubEntries("".$tocStringLocal); } if (@instanceMethods) { if ($class eq "HeaderDoc::Header") { $tocString .= "\n"; } elsif ($self->outputformat eq "html") { if ($newTOC) { $tocString .= $self->tocAccess("Instance Methods", $firstaccess); } else { $tocString .= "
Instance Methods
\n"; } } else { } $firstaccess = 0; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @instanceMethods; } else { @tempobjs = @instanceMethods; } my $tocStringLocal = ""; foreach my $obj (@tempobjs) { my $name = $obj->name(); my $urlname = $obj->apiuid(); if (length($name) > 30) { $name =~ s/:/:\‍/g; } $baseref = "Methods/Methods.html"; if ($composite) { $baseref = $compositePageName; } if ($newTOC) { $tocStringLocal .= tocSubEntry("$baseref#$urlname", "doc", $name); } elsif ($HeaderDoc::use_iframes) { $tocStringLocal .= "      -$name
\n"; } else { $tocStringLocal .= "      -$name
\n"; } } $tocString .= tocWrapSubEntries("".$tocStringLocal); if ($newTOC) { $tocString .= $self->tocAccessEnd(); } } if (!($group eq "")) { if ($newTOC) { # $tocString .= tocGroupEnd($group); } else { $tocString .= "

\n"; } } } $tocString .= $self->tocGroupEnd(); if ($newTOC) { $tocString .= $self->tocHeadingEnd(); } } if (@typedefs) { my $head = "Defined Types\n"; my $baseref = "DataTypes/DataTypes.html"; if ($composite) { $baseref = $compositePageName; } $tocString .= $self->tocStringSub($head, \@groups, \@typedefs, $compositePageName, $baseref, $composite, 1, "datatypes", $newTOC); } if (@structs) { my $head = "Structs and Unions\n"; my $baseref = "Structs/Structs.html"; if ($composite) { $baseref = $compositePageName; } $tocString .= $self->tocStringSub($head, \@groups, \@structs, $compositePageName, $baseref, $composite, 1, "structs", $newTOC); } if (@constants) { my $head = "Constants\n"; my $baseref = "Constants/Constants.html"; if ($composite) { $baseref = $compositePageName; } $tocString .= $self->tocStringSub($head, \@groups, \@constants, $compositePageName, $baseref, $composite, 1, "constants", $newTOC); } if (@enums) { my $head = "Enumerations\n"; my $baseref = "Enums/Enums.html"; if ($composite) { $baseref = $compositePageName; } $tocString .= $self->tocStringSub($head, \@groups, \@enums, $compositePageName, $baseref, $composite, 1, "enums", $newTOC); } if (@pDefines) { my $head = "#defines\n"; my $baseref = "PDefines/PDefines.html"; if ($composite) { $baseref = $compositePageName; } $tocString .= $self->tocStringSub($head, \@groups, \@pDefines, $compositePageName, $baseref, $composite, 1, "defines", $newTOC); } if (@classes) { my @realclasses = (); my @comints = (); foreach my $obj (@classes) { if ($obj->isInternal() && !$HeaderDoc::document_internal) { next; } if ($obj->isCOMInterface()) { push(@comints, $obj); } else { push(@realclasses, $obj); } } if (@realclasses) { @classes = @realclasses; if ($newTOC) { $tocString .= $self->tocHeading("$baseref#HeaderDoc_classes", "Classes", "doc"); } elsif ($HeaderDoc::use_iframes) { $tocString .= "

Classes

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

Classes

\n"; } $tocString .= $self->tocStringSubForClasses("", \@groups, \@classes, $compositePageName, "Classes/{}/$defaultFrameName", $composite, 1, "", $newTOC); $tocString .= $self->tocHeadingEnd() if ($newTOC); } if (@comints) { @classes = @comints; if ($newTOC) { $tocString .= $self->tocHeading("$baseref#HeaderDoc_cominterfaces", "C Pseudoclasses", "doc"); } elsif ($HeaderDoc::use_iframes) { $tocString .= "

C Pseudoclasses

\n"; } else { # $tocString .= "

C Pseudoclasses

\n"; $tocString .= "

C Pseudoclasses

\n"; } my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @classes; } else { @tempobjs = @classes; } $tocString .= $self->tocStringSubForClasses("", \@groups, \@comints, $compositePageName, "Classes/{}/$defaultFrameName", $composite, 1, "", $newTOC); $tocString .= $self->tocHeadingEnd() if ($newTOC); } } if (@protocols) { if ($newTOC) { $tocString .= $self->tocHeading("$baseref#HeaderDoc_protocols", "Protocols", "doc"); } elsif ($HeaderDoc::use_iframes) { $tocString .= "

Protocols

\n"; } else { # $tocString .= "

Protocols

\n"; $tocString .= "

Protocols

\n"; } $tocString .= $self->tocStringSubForClasses("", \@groups, \@protocols, $compositePageName, "Protocols/{}/$defaultFrameName", $composite, 1, "", $newTOC); $tocString .= $self->tocHeadingEnd() if ($newTOC); } if (@categories) { if ($newTOC) { $tocString .= $self->tocHeading("$baseref#HeaderDoc_categories", "Categories", "doc"); } elsif ($HeaderDoc::use_iframes) { $tocString .= "

Categories

\n"; } else { # $tocString .= "

Categories

\n"; $tocString .= "

Categories

\n"; } $tocString .= $self->tocStringSubForClasses("", \@groups, \@categories, $compositePageName, "Categories/{}/$defaultFrameName", $composite, 1, "", $newTOC); $tocString .= $self->tocHeadingEnd() if ($newTOC); } if (@properties) { my $propname = "Properties"; my $baseref = "Properties/Properties.html"; if ($composite) { $baseref = $compositePageName; } $tocString .= $self->tocStringSub($propname, \@groups, \@properties, $compositePageName, $baseref, $composite, 1, "props", $newTOC); } if (@vars) { my $globalname = "Globals"; if ($class ne "HeaderDoc::Header") { $globalname = "Member Data"; } my $baseref = "Vars/Vars.html"; if ($composite) { $baseref = $compositePageName; } $tocString .= $self->tocStringSub($globalname, \@groups, \@vars, $compositePageName, $baseref, $composite, 0, "vars", $newTOC); } if ($class ne "HeaderDoc::Header") { if ($newTOC) { $tocString .= $self->tocSeparator("Other Reference", $newTOC); $tocString .= $self->tocEntry("../../$defaultFrameName", "Header", "_top"); } else { $tocString .= "

Other Reference


\n"; $tocString .= "      Header
\n"; } $tocString .= "\n"; $tocString .= "\n"; } else { $tocString .= "\n"; $tocString .= "\n"; } if (!$composite) { if ($newTOC) { $tocString .= $self->tocEntry("$compositePageName", "[Printable HTML Page]", "_blank"); } else { if ($HeaderDoc::use_iframes) { $tocString .= "

[Printable HTML Page]\n"; } else { $tocString .= "

[Printable HTML Page]\n"; } } } if ($newTOC != 3) { my $availability = $self->availability(); my $updated = $self->updated(); if (length($availability)) { $tocString .= "

Availability: $availability

"; } if (length($updated)) { $tocString .= "

Updated: $updated

"; } } return $tocString; } # /*! # @abstract # Returns a TOC separator block. # */ sub tocSeparator { my $self = shift; my $string = shift; my $newTOC = shift; my $tocString = ""; if ($newTOC == 5) { $tocString .= "


\n"; $tocString .= "

Other Reference

\n"; } return $tocString; } # /*! # @abstract # Returns the HTML for a TOC section heading. # @discussion # Part of the new-style TOC code. # */ sub tocHeading { my $self = shift; my $url = shift; my $name = shift; my $target = shift; my $string = ""; if ($HeaderDoc::use_iframes && $target eq "_top" || $target eq "doc") { $target = "_top"; } if ($HeaderDoc::newTOC == 3) { return tocJSON($url, $name, 1, "tocHeading", undef); } elsif ($HeaderDoc::newTOC == 2) { $string = "
  • "; if ($target ne "") { $string .= "$name\n"; } else { $string .= "$name\n"; } $string .= "\n
  • \n"; } my $string = ""; $string .= "\n"; return $string; } # /*! @abstract # Returns the HTML for a top-level entry in the left-side TOC. # @discussion # In practice, this is used for the Overview section link and the # link back to the enclosing header from a class. # */ sub tocEntry { my $self = shift; my $url = shift; my $name = shift; my $target = "doc"; if (@_) { $target = shift; } if ($HeaderDoc::use_iframes && $target eq "_top" || $target eq "doc") { $target = "_top"; } if ($HeaderDoc::newTOC == 3) { return tocJSON($url, $name, 0, "tocEntry", undef); } elsif ($HeaderDoc::newTOC == 2) { return "
  • $name
  • \n"; } my $tocString = ""; $tocString .= "
    \n"; $tocString .= "\n"; my $style1 = ""; my $style2 = ""; my $style3 = ""; my $width1 = ""; if ($HeaderDoc::newTOC != 5) { $tocString .= "\n"; $style1 = "width=\"10\" style='min-width: 10px; min-height: 1px;'"; $style2 = "width=\"10\" style='min-width: 10px; min-height: 1px;'"; $style3 = "style=\"padding-right: 5px; padding-top: 3px; padding-bottom: 3px;\""; $width1 = "width=\"10\""; } $tocString .= "\n"; # $tocString .= "\n"; $tocString .= "
    $name
    \n"; $tocString .= "
    \n"; return $tocString; } # /*! @abstract # Returns the HTML for the end of a # {@link //apple_ref/perl/cl/HeaderDoc::Group Group} # label in the left-side TOC. # @discussion # Part of the new-style TOC code. # */ sub tocGroupEnd { my $group = shift; my $tocString = ""; if ($HeaderDoc::newTOC == 3) { return tocJSON("", "", 2, "tocGroupEnd", undef); } return ""; } # /*! @abstract # Returns the HTML for a # {@link //apple_ref/perl/cl/HeaderDoc::Group Group} # label in the left-side TOC. # @discussion # Part of the new-style TOC code. # */ sub tocGroup { my $group = shift; my $firstgroup = shift; my $tocString = ""; if (!$firstgroup) { $tocString .= " 
    \n"; } my $preface = "  "; # $tocString .= "$preface$group:
    "; $tocString .= "$group\n"; if ($HeaderDoc::newTOC == 3) { my $url = "index.html#"; return tocJSON($url, $group, 1, "tocGroup", undef); } elsif ($HeaderDoc::newTOC == 2) { $tocString = "
  • $tocString
  • \n"; } return $tocString; } # /*! # @abstract # Returns whether access control is supported by the current programming language. # @result # Returns 1 if the programming language for this object supports # access control, else 0. # */ sub langSupportsAccess { my $self = shift; my $lang = $self->lang(); if ($lang eq "perl" || $lang eq "php" || $lang eq "tcl") { return 0; } return 1; } # /*! @abstract # Returns the HTML for an access heading (e.g. public, private) in the left-side TOC. # @discussion # Part of the new-style TOC code. # */ sub tocAccess { my $self = shift; my $access = shift; my $firstaccess = shift; my $tocString = ""; # print STDERR "TOCACCESS\n"; my $lang = $self->lang(); if (!($self->langSupportsAccess())) { return ""; } if (!$firstaccess) { $tocString .= " 
    \n"; } # $tocString .= "    $access
    \n"; $tocString .= "$access\n"; if ($HeaderDoc::newTOC == 3) { my $url = "index.html#"; return tocJSON($url, $access, 1, "tocAccess", undef); } elsif ($HeaderDoc::newTOC == 2) { $tocString = "
  • $tocString
  • \n"; } return $tocString; } # /*! @abstract # Returns the HTML for closing an access group (e.g. public, private) in the left-side TOC. # @discussion # Part of the new-style TOC code. # */ sub tocAccessEnd { my $self = shift; my $access = shift; my $tocString = ""; # print STDERR "TOCACCESSEND\n"; my $lang = $self->lang(); if ($lang eq "perl" || $lang eq "php" || $lang eq "tcl") { return ""; } if ($HeaderDoc::newTOC == 3) { my $url = ""; return tocJSON($url, $access, 2, "tocAccessEnd", undef); } # $tocString .= "\n"; return $tocString; } # /*! @abstract # Returns an entry for a single symbol in the left-side TOC. # @discussion # Part of the new-style TOC code. # */ sub tocSubEntry { my $url = shift; my $target = shift; my $name = shift; my $tocString = ""; if ($HeaderDoc::use_iframes && $target eq "_top" || $target eq "doc") { $target = "_top"; } # FOR NOW --DAG my $entrypreface = "      "; # $tocString .= "$entrypreface$name
    \n"; if ($HeaderDoc::newTOC == 3) { return tocJSON($url, $name, 0, "tocSubEntry", undef); } elsif ($HeaderDoc::newTOC == 2) { $tocString .= "
  • $name
  • \n"; } else { $tocString .= "
  • $name
  • \n"; } return $tocString; } # /*! @abstract # Returns the structure for a grouping of symbols in the left-side TOC. # @discussion # Part of the new-style TOC code. # */ sub tocWrapSubEntries { my $input = shift; # die("NT: ".$HeaderDoc::newTOC."\n"); if (($HeaderDoc::newTOC == 5) && ($input)) { return ""; } else { return $input; } } # /*! @abstract # Gets/sets the array of enums that are enclosed in this header or class. # @param self # The APIOwner object. # @param ENUMS # The array value to set. (Optional) # */ sub enums { my $self = shift; if (@_) { @{ $self->{ENUMS} } = @_; } ($self->{ENUMS}) ? return @{ $self->{ENUMS} } : return (); } # /*! @abstract # Adds an enum associated with this header or class. # @param self # The APIOwner object. # @param ENUMS # The {@link //apple_ref/perl/cl/HeaderDoc::Enum HeaderDoc::Enum} objects to add. # */ sub addToEnums { my $self = shift; if (@_) { foreach my $item (@_) { if ($addToDebug) { print STDERR "ADDED $item TO ENUMS\n"; } if (!$item->{INSERTED}) { $item->{INSERTED} = 42; } push (@{ $self->{ENUMS} }, $item); } } return @{ $self->{ENUMS} }; } # /*! @abstract # Gets/sets the array of #define entries that are # enclosed in this header. # @param self # The APIOwner object. # @param PDEFINES # The array value to set. (Optional) # */ sub pDefines { my $self = shift; if (@_) { @{ $self->{PDEFINES} } = @_; } ($self->{PDEFINES}) ? return @{ $self->{PDEFINES} } : return (); } # /*! @abstract # Adds a #define macro associated with this header. # @param self # The APIOwner object. # @param PDEFINES # The {@link //apple_ref/perl/cl/HeaderDoc::PDefine HeaderDoc::PDefine} objects to add. # */ sub addToPDefines { my $self = shift; if (@_) { foreach my $item (@_) { if ($addToDebug) { print STDERR "ADDED $item TO PDEFINES\n"; } if (!$item->{INSERTED}) { $item->{INSERTED} = 42; } push (@{ $self->{PDEFINES} }, $item); } } return @{ $self->{PDEFINES} }; } # /*! @abstract # Gets/sets the array of constants that are enclosed in this header or class. # @param self # The APIOwner object. # @param CONSTANTS # The array value to set. (Optional) # */ sub constants { my $self = shift; if (@_) { @{ $self->{CONSTANTS} } = @_; } ($self->{CONSTANTS}) ? return @{ $self->{CONSTANTS} } : return (); } # /*! @abstract # Adds a constant associated with this header or class. # @param self # The APIOwner object. # @param CONSTANTS # The {@link //apple_ref/perl/cl/HeaderDoc::Constant HeaderDoc::Constant} objects to add. # */ sub addToConstants { my $self = shift; if (@_) { foreach my $item (@_) { if ($addToDebug) { print STDERR "ADDED $item TO CONSTANTS\n"; } if (!$item->{INSERTED}) { $item->{INSERTED} = 42; } push (@{ $self->{CONSTANTS} }, $item); } } return @{ $self->{CONSTANTS} }; } # /*! @abstract # Gets/sets the array of functions that are enclosed in this header or class. # @param self # The APIOwner object. # @param FUNCTIONS # The array value to set. (Optional) # */ sub functions { my $self = shift; if (@_) { @{ $self->{FUNCTIONS} } = @_; } ($self->{FUNCTIONS}) ? return @{ $self->{FUNCTIONS} } : return (); } # /*! @abstract # Adds a function associated with this header or class. # @param self # The APIOwner object. # @param FUNCTIONS # The {@link //apple_ref/perl/cl/HeaderDoc::Function HeaderDoc::Function} objects to add. # */ sub addToFunctions { my $self = shift; my $localDebug = 0; if (@_) { foreach my $item (@_) { if ($addToDebug) { print STDERR "ADDED $item TO FUNCTIONS\n"; } # cluck("ADDING FUNCTION $item TO $self\n"); if (!$item->{INSERTED}) { $item->{INSERTED} = 42; } foreach my $compare (@{ $self->{FUNCTIONS} }) { my $name1 = $item->name(); my $name2 = $compare->name(); # print STDERR "ITEM: $item COMPARE: $compare\n"; if ($item->name() eq $compare->name() && $item != $compare) { my $oldconflict = ($item->conflict() && $compare->conflict()); $item->conflict(1); $compare->conflict(1); my $prevignore = $HeaderDoc::ignore_apiuid_errors; $HeaderDoc::ignore_apiuid_errors = 1; my $junk = $item->apirefSetup(1); $junk = $compare->apirefSetup(1); $HeaderDoc::ignore_apiuid_errors = $prevignore; print STDERR "$name1 = $name2\n" if ($localDebug); if (!$oldconflict) { my $apio = $self; # ->apiOwner(); my $apioclass = ref($apio) || $apio; if ($apioclass ne "HeaderDoc::CPPClass") { if ($apioclass !~ /HeaderDoc::ObjC/o) { warn "----------------------------------------------------------------------------\n"; warn "Conflicting declarations for function/method ($name1) outside a\n"."class (apioclass=$apioclass). This is probably not what\n"."you want. This warning is usually caused by failing to include a\n"."HeaderDoc comment for the enclosing class or by using the wrong name\n"."with an old-style HeaderDoc tag such as \@function.\n"; warn "----------------------------------------------------------------------------\n"; # $apio->dbprint(); } } } } elsif ($item == $compare) { # warn "Attempt to reregister object\n"; return; } } push (@{ $self->{FUNCTIONS} }, $item); } } return @{ $self->{FUNCTIONS} }; } # /*! # @abstract # Removes a maximum of one function per invocation. # @discussion # A function gets removed if it gets merged into a C # pseudoclass by an \@alsoInclude directive. # @param self # The APIOwner object. # @param obj # The function object to remove. # */ sub removeFromFunctions { my $self = shift; my $obj = shift; $self->removeObject("FUNCTIONS", $obj); } # /*! # @abstract # Removes a maximum of one #define macro per invocation. # @discussion # A #define gets removed if it gets merged into a C # pseudoclass by an \@alsoInclude directive. # @param self # The APIOwner object. # @param obj # The #define object to remove. # */ sub removeFromPDefines { my $self = shift; my $obj = shift; $self->removeObject("PDEFINES", $obj); } # /*! # @abstract # Removes a maximum of one object per invocation. # @discussion # Used by {@link removeFromFunctions} and {@link removeFromPDefines}. # @param self # The APIOwner object. # @param obj # The object to remove. # */ sub removeObject { my $self = shift; my $key = shift; my $objectToRemove = shift; my @orig = @{$self->{$key}}; my @new = (); my $found = 0; foreach my $obj (@orig) { if ($obj == $objectToRemove) { $found = 1; } else { push(@new, $obj); } } if ($found) { $self->{$key} = \@new; } else { warn "Could not remove ".$objectToRemove->name()." from ".$self->name()."\n"; } } # /*! @abstract # Gets/sets the array of Objective-C methods that are # enclosed in this class. # @param self # The APIOwner object. # @param METHODS # The array value to set. (Optional) # */ sub methods { my $self = shift; if (@_) { @{ $self->{METHODS} } = @_; } ($self->{METHODS}) ? return @{ $self->{METHODS} } : return (); } # /*! @abstract # Adds an Objective-C method associated with this class. # @param self # The APIOwner object. # @param METHODS # The {@link //apple_ref/perl/cl/HeaderDoc::Method HeaderDoc::Method} objects to add. # */ sub addToMethods { my $self = shift; if (@_) { foreach my $item (@_) { if ($addToDebug) { print STDERR "ADDED $item TO METHODS\n"; } if (!$item->{INSERTED}) { $item->{INSERTED} = 42; } foreach my $compare (@{ $self->{METHODS} }) { if ($item->name() eq $compare->name()) { $item->conflict(1); $compare->conflict(1); } } push (@{ $self->{METHODS} }, $item); # warn("addToMethods: ".$item->rawname()."\n"); } } return @{ $self->{METHODS} }; } # /*! @abstract # Gets/sets the array of typedefs that are enclosed in this header or class. # @param self # The APIOwner object. # @param TYPEDEFS # The array value to set. (Optional) # */ sub typedefs { my $self = shift; if (@_) { @{ $self->{TYPEDEFS} } = @_; } ($self->{TYPEDEFS}) ? return @{ $self->{TYPEDEFS} } : return (); } # /*! @abstract # Adds a typedef associated with this header or class. # @param self # The APIOwner object. # @param TYPEDEFS # The {@link //apple_ref/perl/cl/HeaderDoc::Typedef HeaderDoc::Typedef} objects to add. # */ sub addToTypedefs { my $self = shift; if (@_) { foreach my $item (@_) { if ($addToDebug) { print STDERR "ADDED $item TO TYPEDEFS\n"; } if (!$item->{INSERTED}) { $item->{INSERTED} = 42; } push (@{ $self->{TYPEDEFS} }, $item); # print STDERR "added ".$item->name()." to $self.\n"; } } return @{ $self->{TYPEDEFS} }; } # /*! @abstract # Gets/sets the array of structs that are enclosed in this header or class. # @param self # The APIOwner object. # @param STRUCTS # The array value to set. (Optional) # */ sub structs { my $self = shift; if (@_) { @{ $self->{STRUCTS} } = @_; } ($self->{STRUCTS}) ? return @{ $self->{STRUCTS} } : return (); } # /*! @abstract # Adds a struct associated with this header or class. # @param self # The APIOwner object. # @param STRUCTS # The {@link //apple_ref/perl/cl/HeaderDoc::Struct HeaderDoc::Struct} objects to add. # */ sub addToStructs { my $self = shift; if (@_) { foreach my $item (@_) { if ($addToDebug) { print STDERR "ADDED $item TO STRUCTS\n"; } if (!$item->{INSERTED}) { $item->{INSERTED} = 42; } push (@{ $self->{STRUCTS} }, $item); } } return @{ $self->{STRUCTS} }; } # /*! @abstract # Gets/sets the array of properties that are enclosed in this class. # @param self # The APIOwner object. # @param PROPS # The array value to set. (Optional) # */ sub props { my $self = shift; if (@_) { @{ $self->{PROPS} } = @_; } ($self->{PROPS}) ? return @{ $self->{PROPS} } : return (); } # /*! @abstract # Adds a property associated with this class. # @param self # The APIOwner object. # @param PROPS # The {@link //apple_ref/perl/cl/HeaderDoc::Var HeaderDoc::Var} objects # (with isProperty set to 1) to add. # */ sub addToProps { my $self = shift; if (@_) { foreach my $item (@_) { if ($addToDebug) { print STDERR "ADDED $item TO PROPS\n"; } if (!$item->{INSERTED}) { $item->{INSERTED} = 42; } push (@{ $self->{PROPS} }, $item); } } return @{ $self->{PROPS} }; } # /*! @abstract # Gets/sets the array of variables that are enclosed in this header or class. # @param self # The APIOwner object. # @param VARS # The array value to set. (Optional) # */ sub vars { my $self = shift; if (@_) { @{ $self->{VARS} } = @_; } ($self->{VARS}) ? return @{ $self->{VARS} } : return (); } # /*! @abstract # Adds a variable associated with this header or class. # @param self # The APIOwner object. # @param VARS # The {@link //apple_ref/perl/cl/HeaderDoc::Var HeaderDoc::Var} objects # (with isProperty set to 0) to add. # */ sub addToVars { my $self = shift; if (@_) { foreach my $item (@_) { if ($addToDebug) { print STDERR "ADDED $item TO VARS\n"; } if (!$item->{INSERTED}) { $item->{INSERTED} = 42; } push (@{ $self->{VARS} }, $item); } } return @{ $self->{VARS} }; } # /*! @abstract # Gets/sets the array of fields that are associated with a # C pseudoclass. # @param self # The APIOwner object. # @param VARS # The array value to set. (Optional) # */ sub fields { my $self = shift; if (@_) { @{ $self->{FIELDS} } = @_; } ($self->{FIELDS}) ? return @{ $self->{FIELDS} } : return (); } # /*! @abstract # Sets and returns the availability of this class. # @param self # The APIOwner object. # @param availability # The availability value to set. (Optional) # */ sub availability { my $self = shift; if (@_) { $self->{AVAILABILITY} = shift; } return $self->{AVAILABILITY}; } # /*! @abstract # Sets and returns the last updated date for this class or header. # @param self # The APIOwner object. # @param availability # The availability value to set. (Optional) # */ 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 STDERR "updated is $updated\n" if ($localDebug); if (!($updated =~ /\d\d\d\d-\d\d-\d\d/o )) { if (!($updated =~ /\d\d-\d\d-\d\d\d\d/o )) { if (!($updated =~ /\d\d-\d\d-\d\d/o )) { # my $filename = $HeaderDoc::headerObject->filename(); my $fullpath = $self->fullpath(); my $linenum = $self->linenum(); print STDERR "$fullpath:$linenum: warning: Bogus date format: $updated. 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/smog; $day =~ s/\d\d-(\d\d)-\d\d/$1/smog; $year =~ s/\d\d-\d\d-(\d\d)/$1/smog; my $century; $century = `date +%C`; $century *= 100; $year += $century; # $year += 2000; print STDERR "YEAR: $year" if ($localDebug); } } else { print STDERR "03-25-2003 case.\n" if ($localDebug); $month =~ s/(\d\d)-\d\d-\d\d\d\d/$1/smog; $day =~ s/\d\d-(\d\d)-\d\d\d\d/$1/smog; $year =~ s/\d\d-\d\d-(\d\d\d\d)/$1/smog; } } else { $year =~ s/(\d\d\d\d)-\d\d-\d\d/$1/smog; $month =~ s/\d\d\d\d-(\d\d)-\d\d/$1/smog; $day =~ s/\d\d\d\d-\d\d-(\d\d)/$1/smog; } $month =~ s/\n*//smog; $day =~ s/\n*//smog; $year =~ s/\n*//smog; $month =~ s/\s*//smog; $day =~ s/\s*//smog; $year =~ s/\s*//smog; # 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 $fullpath = $self->fullpath(); my $linenum = $self->linenum(); print STDERR "$fullpath:$linenum: warning: Invalid date (year = $year, month = $month, day = $day). Valid formats are MM-DD-YYYY, MM-DD-YY, and YYYY-MM-DD\n"; return $self->{UPDATED}; } else { $self->{UPDATED} =HeaderDoc::HeaderElement::strdate($month-1, $day, $year, $self->encoding()); } } return $self->{UPDATED}; } ################################################################## # # /*! # # @abstract # # Deprecated. # # @discussion # # Creates a book.xml metadata file. No longer used. # # @param self # # The APIOwner object. # # */ # 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; # } # use Devel::Peek; # /*! # @abstract # Creates the index.html frameset file for a class or header. # @param self # The APIOwner object. # */ sub createFramesetFile { my $self = shift; # print STDERR "I0\n"; Dump($self); my $docNavigatorComment = $self->docNavigatorComment(); # print STDERR "I1\n"; Dump($self); my $class = ref($self); my $defaultFrameName = $class->defaultFrameName(); # print STDERR "I2\n"; Dump($self); if ($HeaderDoc::use_iframes) { return; } my $jsnav = 1; my $newTOC = $HeaderDoc::newTOC; my $cols = "190,100%"; my $frameatts = ""; my $bordercolor = ""; my $framesetatts = ""; if ($newTOC) { $cols = "210, *"; $bordercolor = "bordercolor=\"#999999\""; $frameatts = "border=\"0\" frameborder=\"0\""; $framesetatts = "frameborder=\"NO\" border=\"0\""; # frameborder=\"0\""; } # print STDERR "I5\n"; # Dump($self); my $HTMLmeta = ""; # if ($class eq "HeaderDoc::Header") { $HTMLmeta = $self->HTMLmeta(); # } # if ($self->outputformat() eq "html") { # $HTMLmeta .= $self->styleSheet(0); # } 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/o; $rootFileName = &safeName(filename => $rootFileName); my $compositePageName = $self->compositePageName(); my $composite = $HeaderDoc::ClassAsComposite; # if ($class eq "HeaderDoc::Header") { # $composite = 0; # } my $script = ""; if ($jsnav) { $script .= "\n"; } 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$HTMLmeta\n \n\n$script"."\n"; print OUTFILE "\n"; print OUTFILE "\n"; if ($jsnav) { print OUTFILE "\n"; } print OUTFILE "\n"; print OUTFILE "$docNavigatorComment\n"; print OUTFILE "\n"; close OUTFILE; } # /*! # @abstract # Returns a comment marker for # {@link //apple_ref/doc/header/gatherHeaderDoc.pl gatherHeaderDoc}. # @discussion # Overridden by subclasses to return an HTML comment that identifies the # index file (Header vs. Class, name, and so on). The # {@link //apple_ref/doc/header/gatherHeaderDoc.pl gatherHeaderDoc} tool # uses this information to create a master TOC for the generated doc. # @param self # The APIOwner object. # */ sub docNavigatorComment { return ""; } # /*! # @abstract # Creates the table of contents file (toc.html) for a class or header. # @param self # The APIOwner object. # */ sub createTOCFile { my $self = shift; my $rootDir = $self->outputDir(); my $tocTitlePrefix = $self->tocTitlePrefix(); my $outputFileName = "toc.html"; my $depthFile = "$rootDir$pathSeparator$outputFileName"; calcDepth($depthFile); my $newTOC = $HeaderDoc::newTOC; if ($newTOC == 3) { $outputFileName = "book.js"; } my $outputFile = "$rootDir$pathSeparator$outputFileName"; my $fileString = $self->tocString($newTOC); 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)"; } my $HTMLmeta = ""; # if ($class eq "HeaderDoc::Header") { $HTMLmeta = $self->HTMLmeta(); # } # if ($self->outputformat() eq "html") { # $HTMLmeta .= $self->styleSheet(0); # } open(OUTFILE, ">$outputFile") || die "Can't write $outputFile.\n$!\n"; if ($isMacOS) {MacPerl::SetFileInfo('MSIE', 'TEXT', "$outputFile");}; if ($newTOC != 3) { print OUTFILE "\n"; } if ($newTOC == 3) { my @related = (); my %info = ( "technology" => "", "topic" => "", "subtopic" => "", "layer" => "", "framework" => "", # "PDF" => {"href" => ""}, # DO NOT INSERT THIS! "companionFiles" => "", "needsAdditionalLinksSeparator" => "false", "relatedBooks" => \@related ); print OUTFILE tocJSON("", "$tocTitlePrefix $name", 1, "Top", \%info); print OUTFILE $fileString; print OUTFILE tocJSON("", "", 3, "Top", undef); } elsif ($newTOC == 2) { print OUTFILE "\n"; print OUTFILE ""; print OUTFILE "

    $tocTitlePrefix $name

    \n"; print OUTFILE $fileString; } elsif ($newTOC && $newTOC != 5) { print OUTFILE ""; print OUTFILE "\n"; print OUTFILE "\n"; print OUTFILE "\n"; # if ($HeaderDoc::enable_custom_references) { # print OUTFILE "\n"; # } print OUTFILE "\n"; print OUTFILE "\n"; print OUTFILE "Documentation for $title\n$HTMLmeta\n \n"; print OUTFILE $self->styleSheet(1); print OUTFILE "\n"; if ($HeaderDoc::use_iframes) { print OUTFILE "\n"; } else { print OUTFILE "\n"; } print OUTFILE "
    \n"; # Replaced with table. # print OUTFILE "
    \n"; print OUTFILE "
    \n"; print OUTFILE "

    $tocTitlePrefix $name

    \n"; print OUTFILE "
    \n"; print OUTFILE $fileString; # Replaced with table. # print OUTFILE "\n"; print OUTFILE "
    \n"; print OUTFILE "

     

    \n"; print OUTFILE "\n"; } else { print OUTFILE ""; print OUTFILE "\n"; print OUTFILE "\n"; print OUTFILE "Documentation for $title\n$HTMLmeta\n \n\n"; print OUTFILE $self->styleSheet(1); print OUTFILE "\n"; print OUTFILE "\n"; print OUTFILE ""; print OUTFILE ""; print OUTFILE "
     
    "; if ($newTOC != "5") { print OUTFILE "
    "; } # print OUTFILE "

    "; print OUTFILE "\n"; print OUTFILE "\n"; print OUTFILE "\n"; print OUTFILE "\n"; print OUTFILE "
    $tocTitlePrefix
      $name
    \n"; print OUTFILE $fileString; print OUTFILE "

     

    \n"; print OUTFILE "\n"; print OUTFILE "\n"; } close OUTFILE; if ($newTOC == 3) { $HeaderDoc::newTOC = 2; $self->createTOCFile(); $HeaderDoc::newTOC = 3; } } # /*! # @abstract # Generates the content HTML file (right-side frame). # @discussion # In "class as composite" mode, this function does not # get called. Instead, {@link writeHeaderElementsToCompositePage} # is used. # # Otherwise, this function just writes the introduction # for the header or class itself, and the other # right-side content is written later by a call to # {@link writeHeaderElements}. # @param self # The APIOwner object. # */ sub createContentFile { my $self = shift; my $class = ref($self); my $copyrightOwner = $class->copyrightOwner(); my $filename = $self->filename(); my $name = $self->name(); my $title = $filename; my $throws = $self->throws(); if (!length($name)) { $name = "$filename"; } else { $title = "$name ($filename)"; } my $short_attributes = $self->getAttributes(0); my $long_attributes = $self->getAttributes(1); my $list_attributes = $self->getAttributeLists(0); my $newTOC = $HeaderDoc::newTOC; # print STDERR "newTOC: $newTOC\n"; my $rootFileName = $self->filename(); 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(); # } # if ($self->outputformat() eq "html") { # $HTMLmeta .= $self->styleSheet(0); # } my $fileString = ""; $rootFileName =~ s/(.*)\.h/$1/o; # 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 $checkDisc = $self->halfbaked_discussion(); my $headerAbstract = $self->abstract(); if (($checkDisc !~ /\S/) && ($headerAbstract !~ /\S/)) { my $linenum = $self->linenum(); warn "$fullpath:$linenum: No header or class discussion/abstract found. Creating dummy file for default content page.\n"; $headerAbstract .= $HeaderDoc::defaultHeaderComment; # "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"; $fileString .= $self->styleSheet(0); $fileString .= "\n\n"; if ($HeaderDoc::insert_header) { $fileString .= "\n"; $fileString .= $self->htmlHeader()."\n"; $fileString .= "\n"; } $fileString .= "\n"; $fileString .= "

    $name


    \n"; my $namespace = $self->namespace(); my $availability = $self->availability(); my $updated = $self->updated(); my $includeList = ""; if ($class eq "HeaderDoc::Header") { my $includeref = $HeaderDoc::perHeaderIncludes{$filename}; if ($includeref) { my @includes = @{$includeref}; my $first = 1; foreach my $include (@includes) { my $localDebug = 0; print STDERR "Included file: $include\n" if ($localDebug); if (!$first) { if ($newTOC) { $includeList .= "
    \n"; } else { $includeList .= ",\n"; } } my $xmlinc = $self->textToXML($include); my $includeguts = $include; $includeguts =~ s/[<\"](.*)[>\"]/$1/so; my $includefile = basename($includeguts); my $ref = $self->genRefSub("doc", "header", $includefile, ""); $includeList .= "$xmlinc"; $first = 0; } } } if (length($updated) || length($namespace) || length($availability) || length($includeList)) { $fileString .= "

    \n"; } my $attstring = ""; my $c = 0; if (length($namespace)) { if ($newTOC) { if (!$c) { $attstring .= "
    \n"; } $attstring .= "\n"; } else { $attstring .= "Namespace: $namespace
    \n"; } $c++; } if (length($availability)) { if ($newTOC) { if (!$c) { $attstring .= "
    Namespace:
    $namespace
    \n"; } $attstring .= "\n"; } else { $attstring .= "Availability: $availability
    \n"; } $c++; } if (length($updated)) { if ($newTOC) { if (!$c) { $attstring .= "
    Availability:
    $availability
    \n"; } $attstring .= "\n"; } else { $attstring .= "Updated: $updated
    \n"; } $c++; } if (length($includeList)) { if ($newTOC) { if (!$c) { $attstring .= "
    Updated:
    $updated
    \n"; } $attstring .= "\n"; } else { $attstring .= "Includes: "; $attstring .= $includeList; $attstring .= "
    \n"; } $c++; } my $tempstring; my $oldc = $c; if (length($short_attributes)) { $tempstring .= "$short_attributes"; $c++; } if (length($list_attributes)) { $tempstring .= "$list_attributes"; $c++; } if ($newTOC) { # print STDERR "HERE (oldC=$oldc)\n"; if ($c == 2) { $tempstring =~ s/<\/table><\/div>\s*//s; } if ($oldc) { $tempstring =~ s/^\s*//s; } $tempstring =~ s/<\/table><\/div>\s*$//s; } $attstring .= $tempstring; if (!$newTOC) { $attstring .= "
    "; } if (length($throws)) { if ($newTOC) { if (!$c) { $attstring .= "
    Includes:
    $includeList
    \n"; } $attstring .= "\n"; } else { $attstring .= "
    Throws:
    \n
    $throws
    \n"; } $c++; } # if (length($abstract)) { # $fileString .= "
    Abstract:
    \n
    $abstract
    \n"; # } if ($newTOC) { if ($c) { $attstring .= "
    Throws:
    $throws
    \n"; } # Otherwise we do this later. $fileString .= $attstring; } else { $attstring .= ""; } my $uid = $self->apiuid(); 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"; } if (!$newTOC) { # Otherwise we do this earlier. $fileString .= $attstring; } if (length($updated) || length($availability) || length($namespace) || length($headerAbstract) || length($short_attributes) || length($list_attributes) || length($includeList)) { $fileString .= "

    \n"; $fileString .= "

    \n"; } my $discstart = $self->headerDocMark("discussion", "start"); my $discend = $self->headerDocMark("discussion", "end"); if ($self->can("isFramework") && $self->isFramework()) { $fileString .= "\n"; } else { $fileString .= $discstart; } $fileString .= "$headerDiscussion\n"; if ($self->can("isFramework") && $self->isFramework()) { $fileString .= "\n"; } else { $fileString .= $discend; } $fileString .= "

    \n"; if (length($long_attributes)) { $fileString .= "$long_attributes"; } my @fields = $self->fields(); if (@fields) { $fileString .= "
    Template Parameters
    "; # print STDERR "\nGOT fields.\n"; # $fileString .= ""; # $fileString .= ""; $fileString .= "
    "; for my $field (@fields) { my $name = $field->name(); my $desc = $field->discussion(); # print STDERR "field $name $desc\n"; # $fileString .= "
    "; $fileString .= "
    $name
    $desc
    "; } # $fileString .= "
    NameDescription
    $name$desc
    \n"; $fileString .= "\n"; } $fileString .= "

    "; $fileString .= $self->groupDoc("

    Groups

    "); if ($HeaderDoc::insert_header) { $fileString .= "\n"; $fileString .= $self->htmlFooter()."\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(html_fixup_links($self, $fileString)); close OUTFILE; } # /*! # @abstract # Writes a list of functions to standard output. # @discussion # The format of this list is subject to change # without notice. # @param self # The APIOwner object. # */ sub writeFunctionListToStdOut { my $self = shift; my @functions = $self->functions(); my @classes = $self->classes(); my @protocols = $self->protocols(); my @categories = $self->categories(); foreach my $function (@functions) { print "FUNCTION: ".$function->name()."\n"; # my $tree = ${$function->parseTree()}; # print STDERR "PT: $tree\n"; # bless($tree, "HeaderDoc::ParseTree"); # $tree->dbprint(); # $function->dbprint(); my @lines = split(/\n/, $function->functionContents()); foreach my $line (@lines) { print "\t$line\n"; # guarantee each line is indented for easy splitting in shell scripts later. } } foreach my $class (@classes) { $class->writeFunctionListToStdOut(); } foreach my $protocol (@protocols) { $protocol->writeFunctionListToStdOut(); } foreach my $category (@categories) { $category->writeFunctionListToStdOut(); } return; } # /*! # @abstract # Recursively ensures that the {@link apirefSetup} method has been called # on everything that might get emitted later. # */ sub setupAPIReferences { my $self = shift; my @functions = $self->functions(); my @methods = $self->methods(); my @constants = $self->constants(); my @typedefs = $self->typedefs(); my @structs = $self->structs(); my @vars = $self->vars(); my @local_vars = (); if ($self->can("variables")) { @local_vars = $self->variables(); } my @enums = $self->enums(); my @pDefines = $self->pDefines(); my @classes = $self->classes(); my @categories = $self->categories(); my @protocols = $self->protocols(); my @properties = $self->props(); # pre-process everything to make sure we don't have any unregistered # api refs. my $prevignore = $HeaderDoc::ignore_apiuid_errors; $HeaderDoc::ignore_apiuid_errors = 1; my $junk = ""; if (@functions) { foreach my $obj (@functions) { $junk = $obj->apirefSetup();}} if (@methods) { foreach my $obj (@methods) { $junk = $obj->apirefSetup();}} if (@constants) { foreach my $obj (@constants) { $junk = $obj->apirefSetup();}} if (@typedefs) { foreach my $obj (@typedefs) { $junk = $obj->apirefSetup();}} if (@structs) { foreach my $obj (@structs) { $junk = $obj->apirefSetup();}} if (@local_vars) { foreach my $obj (@local_vars) { $junk = $obj->apirefSetup();}} if (@vars) { foreach my $obj (@vars) { $junk = $obj->apirefSetup();}} if (@enums) { foreach my $obj (@enums) { $junk = $obj->apirefSetup();}} if (@pDefines) { foreach my $obj (@pDefines) { $junk = $obj->apirefSetup();}} if (@classes) { foreach my $obj (@classes) { $junk = $obj->apirefSetup(); $junk = $obj->docNavigatorComment(); $obj->setupAPIReferences(); }} if (@categories) { foreach my $obj (@categories) { $junk = $obj->apirefSetup(); $junk = $obj->docNavigatorComment(); $obj->setupAPIReferences(); }} if (@protocols) { foreach my $obj (@protocols) { $junk = $obj->apirefSetup(); $junk = $obj->docNavigatorComment(); $obj->setupAPIReferences(); }} if (@properties) { foreach my $obj (@properties) { $junk = $obj->apirefSetup();}} $HeaderDoc::ignore_apiuid_errors = $prevignore; } # /*! # @abstract # Writes the right-side content. # @discussion # In "class as composite" mode, this function's # purpose is handled by {@link writeHeaderElementsToCompositePage}, # so it does not get called. # # Otherwise, this function writes all of the # right-side content frames (e.g. Methods/Methods.html) # except for the introduction (which is written # by {@link writeHeaderElements}). # @param self # The APIOwner object. # */ 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 $propsDir = $self->propsDir(); my $enumsDir = $self->enumsDir(); my $pDefinesDir = $self->pDefinesDir(); my $classesDir = $self->classesDir(); my $protocolsDir = $self->protocolsDir(); my $categoriesDir = $self->categoriesDir(); if (! -e $rootOutputDir) { unless (mkdir ("$rootOutputDir", 0777)) {die ("Can't create output folder $rootOutputDir. \n$!");}; } my $junk = ""; my @functions = $self->functions(); my @methods = $self->methods(); my @constants = $self->constants(); my @typedefs = $self->typedefs(); my @structs = $self->structs(); my @vars = $self->vars(); my @local_vars = (); if ($self->can("variables")) { @local_vars = $self->variables(); } my @enums = $self->enums(); my @pDefines = $self->pDefines(); my @classes = $self->classes(); my @properties = $self->props(); # Check point. # if (1) { # print STDERR "CLASS LIST FOR $self (".$self->name().")\n"; # foreach my $class (@classes) { # print STDERR "CLASS: $class (".$class->name().")\n"; # } # } if (!$HeaderDoc::ClassAsComposite) { 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->props()) { if (! -e $propsDir) { unless (mkdir ("$propsDir", 0777)) {die ("Can't create output folder $propsDir. \n$!");}; } $self->writeProps(); } 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(); } } # Always do this to create directories for nested classes. if ($self->classes()) { if (! -e $classesDir) { unless (mkdir ("$classesDir", 0777)) {die ("Can't create output folder $classesDir. \n$!");}; } $self->writeClasses(); } if ($self->protocols()) { if (! -e $protocolsDir) { unless (mkdir ("$protocolsDir", 0777)) {die ("Can't create output folder $protocolsDir. \n$!\n");}; } $self->writeProtocols(); } if ($self->categories()) { if (! -e $categoriesDir) { unless (mkdir ("$categoriesDir", 0777)) {die ("Can't create output folder $categoriesDir. \n$!\n");}; } $self->writeCategories(); } } # /*! # @abstract # Writes a Doxygen-style tag file. # @param self # The APIOwner object. # @discussion # This function does not write the final tag file. # Instead, it writes a partial tag file that # represents the contents of a single header. # At the end of processing, HeaderDoc combines # these into a single tag file. # */ sub writeHeaderElementsToDoxyFile { # Write a Doxygen-style tag file. my $self = shift; my $prespace = ""; my $class = ref($self); my $doxyFilename = "doxytags.doxytagtemp"; my $rootOutputDir = $self->outputDir(); my $name = $self->name(); my $doxyFileString = "\n".$self->_getDoxyTagString($prespace." ")."\n"; my $outputFile = $rootOutputDir.$pathSeparator.$doxyFilename; if (! -e $rootOutputDir) { unless (mkdir ("$rootOutputDir", 0777)) {die ("Can't create output folder $rootOutputDir. $!");}; } if ($self->use_stdout()) { open(OUTFILE, ">&STDOUT"); } else { open(OUTFILE, ">$outputFile") || die "Can't write $outputFile.\n"; } print OUTFILE $doxyFileString; close OUTFILE; } # /*! # @abstract # Returns a Doxygen-style tagfile string. # @param self # The APIOwner object. # @discussion # Called by {@link writeHeaderElementsToDoxyFile}. # */ sub _getDoxyTagString { my $self = shift; my $prespace = shift; my $name = $self->name(); my $doxykind = $self->getDoxyKind(); my $doxyFileString = "$prespace\n"; $doxyFileString .= "$prespace".$self->textToXML($self->rawname())."\n"; if ($doxykind eq "file") { $doxyFileString .= "$prespace".$self->textToXML($self->fullpath())."\n"; } if ($self->checkShortLongAttributes("Superclass")) { my $inherits = $self->textToXML($self->checkShortLongAttributes("Superclass")); $inherits =~ s/\cA/,/sg; $inherits =~ s/\s+/ /sg; $inherits =~ s/^\s*//sg; $inherits =~ s/\s*$//sg; $doxyFileString .= "$prespace ".$inherits."\n"; } if ($self->checkShortLongAttributes("Implements Class")) { $doxyFileString .= "$prespace ".$self->textToXML($self->checkShortLongAttributes("Extends Class"))."\n"; } if ($self->checkShortLongAttributes("Extends Class")) { $doxyFileString .= "$prespace ".$self->textToXML($self->checkShortLongAttributes("Extends Class"))."\n"; } if ($self->checkShortLongAttributes("Extends Protocol")) { $doxyFileString .= "$prespace ".$self->textToXML($self->checkShortLongAttributes("Extends Class"))."\n"; } my @objects = $self->classes(); foreach my $obj (@objects) { # print "CLASS: $obj\n"; $doxyFileString .= $obj->_getDoxyTagString($prespace." "); } @objects = $self->protocols(); foreach my $obj (@objects) { $doxyFileString .= $obj->_getDoxyTagString($prespace." "); } @objects = $self->categories(); foreach my $obj (@objects) { $doxyFileString .= $obj->_getDoxyTagString($prespace." "); } @objects = $self->functions(); foreach my $obj (@objects) { $doxyFileString .= $obj->_getDoxyTagString($prespace." "); } @objects = $self->methods(); foreach my $obj (@objects) { $doxyFileString .= $obj->_getDoxyTagString($prespace." "); } @objects = $self->constants(); foreach my $obj (@objects) { $doxyFileString .= $obj->_getDoxyTagString($prespace." "); } @objects = $self->typedefs(); foreach my $obj (@objects) { $doxyFileString .= $obj->_getDoxyTagString($prespace." "); } @objects = $self->structs(); foreach my $obj (@objects) { $doxyFileString .= $obj->_getDoxyTagString($prespace." "); } @objects = $self->props(); foreach my $obj (@objects) { $doxyFileString .= $obj->_getDoxyTagString($prespace." "); } @objects = $self->vars(); foreach my $obj (@objects) { $doxyFileString .= $obj->_getDoxyTagString($prespace." "); } @objects = $self->enums(); foreach my $obj (@objects) { $doxyFileString .= $obj->_getDoxyTagString($prespace." "); } @objects = $self->pDefines(); foreach my $obj (@objects) { $doxyFileString .= $obj->_getDoxyTagString($prespace." "); } $doxyFileString .= "$prespace\n"; return $doxyFileString; } # /*! # @abstract # Writes a series of manual pages for a header's functions. # @param self # The APIOwner object. # @discussion # This function requires the xmlman binaries to be # installed in /usr/bin. # */ sub writeHeaderElementsToManPage { my $self = shift; my $class = ref($self); my $compositePageName = $self->filename(); my $localDebug = 0; # $compositePageName =~ s/\.(h|i)$//o; $compositePageName .= ".mxml"; my $rootOutputDir = $self->outputDir(); my $tempOutputDir = $rootOutputDir."/mantemp"; my $XMLPageString = $self->_getXMLPageString(); my $section = $HeaderDoc::man_section; mkdir($tempOutputDir, 0777); my $cwd = cwd(); chdir($tempOutputDir); # print STDERR "SECTION: \"$section\"\n"; open(OUTFILE, "|/usr/bin/hdxml2manxml -M $section"); print OUTFILE $XMLPageString; print STDERR "WROTE: $XMLPageString\n" if ($localDebug); close(OUTFILE); my @files = <*.mxml>; foreach my $file (@files) { system("/usr/bin/xml2man \"$file\""); unlink($file); } chdir($cwd); @files = <${tempOutputDir}/*>; foreach my $file (@files) { my $filename = basename($file); print STDERR "RENAMING $file to $rootOutputDir/$filename\n" if ($localDebug); rename($file, "$rootOutputDir/$filename"); } rmdir("$tempOutputDir"); } # /*! # @abstract # Writes output to an XML file. # @param self # The APIOwner object. # */ sub writeHeaderElementsToXMLPage { # All API in a single XML page my $self = shift; my $class = ref($self); my $compositePageName = $self->filename(); # $compositePageName =~ s/\.(h|i)$//o; $compositePageName .= ".xml"; my $rootOutputDir = $self->outputDir(); my $name = $self->textToXML($self->name()); my $XMLPageString = $self->_getXMLPageString(); my $outputFile = $rootOutputDir.$pathSeparator.$compositePageName; # print STDERR "cpn = $compositePageName\n"; if (!$self->use_stdout()) { if (! -e $rootOutputDir) { unless (mkdir ("$rootOutputDir", 0777)) {die ("Can't create output folder $rootOutputDir. $!");}; } } $self->_createXMLOutputFile($outputFile, xml_fixup_links($self, $XMLPageString), "$name"); } # /*! # @abstract # Writes output to the composite page. # @discussion # In "class as composite" mode, this function supersedes # the function {@link createContentFile}. # @param self # The APIOwner object. # */ 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; # print STDERR "OUTFILE: $outputFile\n"; if (! -e $rootOutputDir) { unless (mkdir ("$rootOutputDir", 0777)) {die ("Can't create output folder $rootOutputDir. $!");}; } # print STDERR "PRE: $compositePageString\n"; my $processed_string = html_fixup_links($self, $compositePageString); # print STDERR "DUMP: $processed_string\n"; $self->_createHTMLOutputFile($outputFile, $processed_string, "$name", 1); } # /*! # @abstract # Writes the protocols in a header object to a composite page. # @param self # The Header object. # */ sub writeProtocols { my $self = shift; my @protocolObjs = $self->protocols(); my $protocolsRootDir = $self->protocolsDir(); my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @protocolObjs; } else { @tempobjs = @protocolObjs; } foreach my $obj (@tempobjs) { my $protocolName = $obj->name(); # for now, always shorten long names since some files may be moved to a Mac for browsing if (1 || $isMacOS) {$protocolName = &safeName(filename => $protocolName);}; $obj->outputDir("$protocolsRootDir$pathSeparator$protocolName"); $obj->createFramesetFile(); $obj->createContentFile() if (!$HeaderDoc::ClassAsComposite); $obj->writeHeaderElementsToCompositePage(); $obj->createTOCFile(); $obj->writeHeaderElements(); } } # /*! # @abstract # Writes the categories in a header object to a composite page. # @param self # The Header object. # */ sub writeCategories { my $self = shift; my @categoryObjs = $self->categories(); my $categoriesRootDir = $self->categoriesDir(); my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @categoryObjs; } else { @tempobjs = @categoryObjs; } foreach my $obj (@tempobjs) { my $categoryName = $obj->name(); # for now, always shorten long names since some files may be moved to a Mac for browsing if (1 || $isMacOS) {$categoryName = &safeName(filename => $categoryName);}; $obj->outputDir("$categoriesRootDir$pathSeparator$categoryName"); $obj->createFramesetFile(); $obj->createContentFile() if (!$HeaderDoc::ClassAsComposite); $obj->writeHeaderElementsToCompositePage(); $obj->createTOCFile(); $obj->writeHeaderElements(); } } # /*! # @abstract # Generates output string for storing in an XML file. # @param self # The APIOwner object. # @discussion # This function is called by {@link writeHeaderElementsToXMLPage}. # */ sub _getXMLPageString { my $self = shift; my $name = $self->name(); my $compositePageString; my $contentString; return $self->XMLdocumentationBlock(0); } # /*! # @abstract # Generates output string for storing in the composite page. # @param self # The APIOwner object. # @discussion # This function is called by {@link writeHeaderElementsToCompositePage}. # */ sub _getCompositePageString { my $self = shift; my $name = $self->name(); my $compositePageString; my $list_attributes = $self->getAttributeLists(1); my $short_attributes = $self->getAttributes(0); my $long_attributes = $self->getAttributes(1); if (!$HeaderDoc::use_iframes) { $compositePageString .= $self->compositePageAPIRef(); } $compositePageString .= $self->documentationBlock(); my $firstsection = 1; my $classEmbeddedTOC = $self->_getClassEmbeddedTOC(1); my $groupDocString = $self->groupDoc("

    Groups

    "); my $functionDocString = $self->_getFunctionDetailString(1); my $methodDocString = $self->_getMethodDetailString(1); my $constantDocString = $self->_getConstantDetailString(1); my $typedefDocString = $self->_getTypedefDetailString(1); my $structDocString = $self->_getStructDetailString(1); my $propDocString = $self->_getPropDetailString(1); my $varDocString = $self->_getVarDetailString(1); my $enumDocString = $self->_getEnumDetailString(1); my $defineDocString = $self->_getPDefineDetailString(1); my $onlyClasses = 1; if ($groupDocString || $functionDocString || $methodDocString || $constantDocString || $typedefDocString || $structDocString || $propDocString || $varDocString || $enumDocString || $defineDocString) { $onlyClasses = 0; } if ((!$onlyClasses) || $classEmbeddedTOC) { # Leave out this if there are no classes and no other API elements. $compositePageString .= "

    "; } if (length($classEmbeddedTOC)) { $compositePageString .= $classEmbeddedTOC; if (!$onlyClasses) { # Classes are special because they contain no documentation # inline other than the links and abstracts. Thus, # the trailing
    tag is only needed if the header # contains other API symbols. $compositePageString .= "

    "; } } if (length($groupDocString)) { $compositePageString .= $groupDocString; # Do NOT do this. There is already an afterGroupHeading marker. # if (!$firstsection) { $compositePageString .= "
    \n"; } # $firstsection = 0; } if (length($functionDocString)) { # $compositePageString .= "

    Functions

    \n"; # $functionDocString = $self->stripAppleRefs($functionDocString); if (!$firstsection) { $compositePageString .= "
    \n"; } $firstsection = 0; $compositePageString .= $functionDocString; } if (length($methodDocString)) { # $compositePageString .= "

    Methods

    \n"; # $methodDocString = $self->stripAppleRefs($methodDocString); if (!$firstsection) { $compositePageString .= "
    \n"; } $firstsection = 0; $compositePageString .= $methodDocString; } if (length($constantDocString)) { # $compositePageString .= "

    Constants

    \n"; # $constantDocString = $self->stripAppleRefs($constantDocString); if (!$firstsection) { $compositePageString .= "
    \n"; } $firstsection = 0; $compositePageString .= $constantDocString; } if (length($typedefDocString)) { # $compositePageString .= "

    Typedefs

    \n"; # $typedefDocString = $self->stripAppleRefs($typedefDocString); if (!$firstsection) { $compositePageString .= "
    \n"; } $firstsection = 0; $compositePageString .= $typedefDocString; } if (length($structDocString)) { # $compositePageString .= "

    Structs and Unions

    \n"; # $structDocString = $self->stripAppleRefs($structDocString); if (!$firstsection) { $compositePageString .= "
    \n"; } $firstsection = 0; $compositePageString .= $structDocString; } if (length($propDocString)) { my $class = ref($self) || $self; # my $globalname = "Properties"; # my $baseref = "Properties/Properties.html"; # $compositePageString .= "

    $globalname

    \n"; # $propDocString = $self->stripAppleRefs($propDocString); if (!$firstsection) { $compositePageString .= "
    \n"; } $firstsection = 0; $compositePageString .= $propDocString; } if (length($varDocString)) { my $class = ref($self) || $self; # my $globalname = "Globals"; # if ($class ne "HeaderDoc::Header") { # $globalname = "Member Data"; # } # my $baseref = "Vars/Vars.html"; # $compositePageString .= "

    $globalname

    \n"; # $varDocString = $self->stripAppleRefs($varDocString); if (!$firstsection) { $compositePageString .= "
    \n"; } $firstsection = 0; $compositePageString .= $varDocString; } if (length($enumDocString)) { # $compositePageString .= "

    Enumerations

    \n"; if (!$firstsection) { $compositePageString .= "
    \n"; } $firstsection = 0; $compositePageString .= $enumDocString; } if (length($defineDocString)) { # $compositePageString .= "

    #defines

    \n"; # $defineDocString = $self->stripAppleRefs($defineDocString); if (!$firstsection) { $compositePageString .= "
    \n"; } $firstsection = 0; $compositePageString .= $defineDocString; } return $compositePageString; } # /*! # @abstract # Strips apple_ref markup from the composite page output. # @param self # The APIOwner object. # @discussion # An apple_ref marker is a named anchor that uniquely identifies # each API symbol. For example, an Objective-C class named Foo # would have the anchor <a name="//apple_ref/occ/cl/Foo"></a>. # This markup is already in the primary documentation pages, so # the duplicates must be removed from the composite pages. See # the {@linkplain //apple_ref/doc/uid/TP40001215-CH347 # Symbol Markers for HTML-Based Documentation} in # {@linkdoc //apple_ref/doc/uid/TP40001215 HeaderDoc User Guide} # to learn more about apple_ref markup. # */ sub stripAppleRefs { my $self = shift; my $string = shift; my $apiUIDPrefix = HeaderDoc::APIOwner->apiUIDPrefix(); $string =~ s|(.*?)<\s*/a\s*>|$1|g; return $string; } # /*! # @abstract # Returns an apple_ref marker for a header/class composite page. # @param self # The APIOwner object. # */ sub compositePageAPIRef { my $self = shift; my $name = $self->name(); my $uid = $self->compositePageAPIUID(); my $apiref = "\n"; return $apiref; } # /*! # @abstract # Returns an apple_ref UID for a header/class composite page. # @param self # The APIOwner object. # @discussion # Called by {@link compositePageAPIRef}. # */ sub compositePageAPIUID { my $self = shift; my $class = ref($self) || $self; my $apiUIDPrefix = HeaderDoc::APIOwner->apiUIDPrefix(); my $type = "header"; SWITCH : { ($class eq "HeaderDoc::CPPClass") && do { $type = "class"; }; ($class eq "HeaderDoc::ObjCCategory") && do { $type = "class"; }; ($class eq "HeaderDoc::ObjCClass") && do { $type = "class"; }; ($class eq "HeaderDoc::ObjCContainer") && do { $type = "class"; }; ($class eq "HeaderDoc::ObjCProtocol") && do { $type = "protocol"; }; } my $shortname = $self->name(); if ($class eq "HeaderDoc::Header") { $shortname = $self->filename(); $shortname =~ s/\.hdoc$//so; } $shortname = sanitize($shortname, 1); if ($self->isFramework()) { $type = "framework"; } # print "TYPE: $type\n"; my $apiuid = "//$apiUIDPrefix/doc/$type/$shortname"; my $requested = $self->requestedUID(); if ($requested) { return $requested; }; return $apiuid; } # /*! # @abstract # Writes the right-side content for functions in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link writeHeaderElements}. # */ sub writeFunctions { my $self = shift; my $functionFile = $self->functionsDir().$pathSeparator."Functions.html"; my $class = ref($self) || $self; my $funchead = "Functions"; if ($class ne "HeaderDoc::Header") { $funchead = "Member Functions"; } $self->_createHTMLOutputFile($functionFile, $self->_getFunctionDetailString(0), $funchead, 0); } # /*! # @abstract # Returns the right-side content for functions in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getCompositePageString} and {@link writeFunctions}. # */ sub _getFunctionDetailString { my $self = shift; my $composite = shift; my @funcObjs = $self->functions(); my $contentString = ""; my $class = ref($self) || $self; my $funchead = "Functions"; if ($class ne "HeaderDoc::Header") { $funchead = "Member Functions"; } # $contentString .= $self->_getFunctionEmbeddedTOC($composite); $contentString .= $self->_getDetailString(\@funcObjs, $composite, "functions", $funchead); return $contentString; # my @tempobjs = (); # if (!$self->unsorted()) { # @tempobjs = sort objName @funcObjs; # } else { # @tempobjs = @funcObjs; # } # foreach my $obj (@tempobjs) { # my $documentationBlock = $obj->documentationBlock($composite); # $contentString .= $documentationBlock; # } # return $contentString; } # /*! # @abstract # Returns the XML content string for functions in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getXMLPageString}. # */ sub _getFunctionXMLDetailString { my $self = shift; my @funcObjs = $self->functions(); my $contentString = ""; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @funcObjs; } else { @tempobjs = @funcObjs; } foreach my $obj (@tempobjs) { my $documentationBlock = $obj->XMLdocumentationBlock(); $contentString .= $documentationBlock; } return $contentString; } # /*! # @abstract # Returns the XML content string for classes in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getXMLPageString}. # */ sub _getEmbeddedClassXMLDetailString { my $self = shift; my $classObjsRef = shift; my @classObjs = @{$classObjsRef}; my $contentString = ""; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @classObjs; } else { @tempobjs = @classObjs; } foreach my $obj (@tempobjs) { # print STDERR "outputting class ".$obj->name."."; my $documentationBlock = $obj->XMLdocumentationBlock(); $contentString .= $documentationBlock; } return $contentString; } # /*! # @abstract # Returns the XML content string for classes in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getXMLPageString}. # */ sub _getClassXMLDetailString { my $self = shift; my @classObjs = $self->classes(); my $contentString = ""; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @classObjs; } else { @tempobjs = @classObjs; } foreach my $obj (@tempobjs) { # print STDERR "outputting class ".$obj->name."."; my $documentationBlock = $obj->XMLdocumentationBlock(); $contentString .= $documentationBlock; } return $contentString; } # /*! # @abstract # Returns the XML content string for categories in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getXMLPageString}. # */ sub _getCategoryXMLDetailString { my $self = shift; my @classObjs = $self->categories(); my $contentString = ""; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @classObjs; } else { @tempobjs = @classObjs; } foreach my $obj (@tempobjs) { # print STDERR "outputting category ".$obj->name."."; my $documentationBlock = $obj->XMLdocumentationBlock(); $contentString .= $documentationBlock; } return $contentString; } # /*! # @abstract # Returns the XML content string for protocols in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getXMLPageString}. # */ sub _getProtocolXMLDetailString { my $self = shift; my @classObjs = $self->protocols(); my $contentString = ""; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @classObjs; } else { @tempobjs = @classObjs; } foreach my $obj (@tempobjs) { # print STDERR "outputting protocol ".$obj->name."."; my $documentationBlock = $obj->XMLdocumentationBlock(); $contentString .= $documentationBlock; } return $contentString; } # /*! # @abstract # Writes the right-side content for methods in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link writeHeaderElements}. # */ sub writeMethods { my $self = shift; my $methodFile = $self->methodsDir().$pathSeparator."Methods.html"; $self->_createHTMLOutputFile($methodFile, $self->_getMethodDetailString(0), "Methods", 0); } # /*! # @abstract # Returns an embedded mini-TOC. # @param self # The APIOwner object. # @param listref # A reference to a list of objects. # @param typeFile # The raw type name (e.g. Functions, Methods). Used for generating # the filename for links. # @param tag # The tag type name (e.g. function). Used for generating the jump # link to the heading. # @param displaytype # The human-readable name of the type. Used in headings. # @param compositePage # Pass 1 if this is being generated for a composite page, else 0. # @param includeObjectName # Pass 1 if the object name is a path component, else 0. # In effect, pass 1 for classes and similar, 0 for normal data types, # functions, variables, etc. # @discussion # This function generates the embedded mini-TOC # that appears at the top of various sections # in the right-side content. # */ sub _getEmbeddedTOC { my $self = shift; my $listref = shift; my $typeFile = shift; my $tag = shift; my $displaytype = shift; my $compositePage = shift; my $includeObjectName = shift; # print STDERR "TYPEFILE: $typeFile\n"; my $group_mode = 0; if (@_) { $group_mode = shift; } my $localDebug = 0; print STDERR "CPAGE: $compositePage\n" if ($localDebug); my @objlist = @{ $listref }; my $eTOCString = ""; my $class = ref($self) || $self; my $compositePageName = $self->compositePageName(); my $processed_tag = $tag; $processed_tag =~ s/\s//sg; $processed_tag = lc($processed_tag); if (!$group_mode) { $eTOCString .= "\n"; } if ($includeObjectName) { $eTOCString .= "

    $displaytype

    \n"; } print STDERR "My class is $class\n" if ($localDebug); if (!scalar(@objlist)) { print STDERR "empty objlist\n" if ($localDebug); return ""; } # if (!($#objlist)) { # print STDERR "empty objlist\n" if ($localDebug); # return ""; # } $eTOCString .= "
    \n"; foreach my $obj (@objlist) { if ($obj->isInternal() && !$HeaderDoc::document_internal) { next; } # print STDERR "@objlist\n"; # print STDERR "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) { $composite = 1; $target = "_top"; } if ($obj->isAPIOwner()) { $target = "_top"; $composite = 0; } if ($HeaderDoc::use_iframes) { $target = "_top"; } my $safeName = $name; $safeName = &safeName(filename => $name); my $urlname = $obj->apiuid(); # sanitize($name); if ($composite && !$HeaderDoc::ClassAsComposite) { $urlname = $obj->compositePageUID(); } # print STDERR "ION: $includeObjectName TF: $typeFile\n"; if (($includeObjectName == 1) && $composite) { $url = "$typeFile/$safeName/$compositePageName#$urlname"; } elsif ($includeObjectName == 1) { $url = "$typeFile/$safeName/index.html#$urlname"; } elsif ($composite) { $url = "$compositePageName#$urlname" } else { $url = "$typeFile#$urlname" } my $parentclass = $obj->origClass(); if (length($parentclass)) { $parentclass .= "::"; } if ($self->CClass()) { # Don't do this for pseudo-classes. $parentclass = ""; } my $objclass = ref($obj) || $obj; if ($obj =~ /HeaderDoc::Method/) { if ($obj->isInstanceMethod() eq "YES") { $parentclass = "-"; } else { $parentclass = "+"; } # print STDERR "OCC: IIM: ".$obj->isInstanceMethod()."\n"; } $eTOCString .= "
    "; if (!$group_mode) { $eTOCString .= "$parentclass$name"; } else { $eTOCString .= "$parentclass$name"; } $eTOCString .= "
    \n"; $eTOCString .= "
    $abstract
    \n"; } $eTOCString .= "
    \n"; print STDERR "etoc: $eTOCString\n" if ($localDebug); return $eTOCString; } # /*! # @abstract # Returns the embedded mini-TOC for classes. # @param self # The APIOwner object. # @discussion # This function generates the embedded mini-TOC # that appears at the top of the Classes section # in the right-side content. # # This function is a wrapper for {@link _getEmbeddedTOC} # that generates separate embedded TOCs for classes, # categories, protocols, and COM interfaces. # */ sub _getClassEmbeddedTOC { my $self = shift; my $composite = shift; my @possclasses = $self->classes(); my @protocols = $self->protocols(); my @categories = $self->categories(); my $localDebug = 0; my $retval = ""; print STDERR "getClassEmbeddedTOC: processing ".$self->name()."\n" if ($localDebug); my @classes = (); my @comints = (); foreach my $class (@possclasses) { if ($class->isCOMInterface()) { push(@comints, $class); } else { push(@classes, $class); } } if (scalar(@classes)) { print STDERR "getClassEmbeddedTOC: classes found.\n" if ($localDebug); my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @classes; } else { @tempobjs = @classes; } if ($localDebug) { foreach my $item(@tempobjs) { print STDERR "TO: $item : ".$item->name()."\n"; } } $retval .= $self->_getEmbeddedTOC(\@tempobjs, "Classes", "classes", "Classes", $composite, 1); } if (scalar(@comints)) { print STDERR "getClassEmbeddedTOC: comints found.\n" if ($localDebug); my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @comints; } else { @tempobjs = @comints; } if ($localDebug) { foreach my $item(@tempobjs) { print STDERR "TO: $item : ".$item->name()."\n"; } } $retval .= $self->_getEmbeddedTOC(\@tempobjs, "Classes", "classes", "C Pseudoclasses", $composite, 1); } if (scalar(@protocols)) { print STDERR "getClassEmbeddedTOC: protocols found.\n" if ($localDebug); my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @protocols; } else { @tempobjs = @protocols; } if ($localDebug) { foreach my $item(@tempobjs) { print STDERR "TO: $item : ".$item->name()."\n"; } } $retval .= $self->_getEmbeddedTOC(\@tempobjs, "Protocols", "protocols", "Protocols", $composite, 1); } if (scalar(@categories)) { print STDERR "getClassEmbeddedTOC: categories found.\n" if ($localDebug); my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @categories; } else { @tempobjs = @categories; } if ($localDebug) { foreach my $item(@tempobjs) { print STDERR "TO: $item : ".$item->name()."\n"; } } $retval .= $self->_getEmbeddedTOC(\@tempobjs, "Categories", "categories", "Categories", $composite, 1); } print STDERR "eClassTOC = $retval\n" if ($localDebug); return $retval; } # /*! # @abstract # Returns the right-side content for methods in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getCompositePageString} and {@link writeMethods}. # */ sub _getMethodDetailString { my $self = shift; my $composite = shift; my @methObjs = $self->methods(); my $contentString = ""; my $localDebug = 0; # $contentString .= $self->_getMethodEmbeddedTOC($composite); $contentString .= $self->_getDetailString(\@methObjs, $composite, "methods", "Methods"); return $contentString; # my @tempobjs = (); # if (!$self->unsorted()) { # @tempobjs = sort objName @methObjs; # } else { # @tempobjs = @methObjs; # } # foreach my $obj (@tempobjs) { # my $documentationBlock = $obj->documentationBlock($composite); # $contentString .= $documentationBlock; # } # return $contentString; } # /*! # @abstract # Returns the XML content string for methods in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getXMLPageString}. # */ sub _getMethodXMLDetailString { my $self = shift; my @methObjs = $self->methods(); my $contentString = ""; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @methObjs; } else { @tempobjs = @methObjs; } foreach my $obj (@tempobjs) { my $documentationBlock = $obj->XMLdocumentationBlock(); $contentString .= $documentationBlock; } return $contentString; } # /*! # @abstract # Writes the right-side content for constants in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link writeHeaderElements}. # */ sub writeConstants { my $self = shift; my $constantsFile = $self->constantsDir().$pathSeparator."Constants.html"; $self->_createHTMLOutputFile($constantsFile, $self->_getConstantDetailString(0), "Constants", 0); } # /*! # @abstract # Returns the right-side content for constants in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getCompositePageString} and {@link writeConstants}. # */ sub _getConstantDetailString { my $self = shift; my $composite = shift; my @constantObjs = $self->constants(); my $contentString; return $self->_getDetailString(\@constantObjs, $composite, "constants", "Constants"); # my @tempobjs = (); # if (!$self->unsorted()) { # @tempobjs = sort objName @constantObjs; # } else { # @tempobjs = @constantObjs; # } # foreach my $obj (@tempobjs) { # my $documentationBlock = $obj->documentationBlock($composite); # $contentString .= $documentationBlock; # } # return $contentString; } # /*! # @abstract # Returns the XML content string for constants in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getXMLPageString}. # */ sub _getConstantXMLDetailString { my $self = shift; my @constantObjs = $self->constants(); my $contentString; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @constantObjs; } else { @tempobjs = @constantObjs; } foreach my $obj (@tempobjs) { my $documentationBlock = $obj->XMLdocumentationBlock(); $contentString .= $documentationBlock; } return $contentString; } # /*! # @abstract # Writes the right-side content for typdefs in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link writeHeaderElements}. # */ sub writeTypedefs { my $self = shift; my $typedefsFile = $self->datatypesDir().$pathSeparator."DataTypes.html"; $self->_createHTMLOutputFile($typedefsFile, $self->_getTypedefDetailString(0), "Defined Types", 0); } # /*! # @abstract # Returns the right-side content for typedefs in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getCompositePageString} and {@link writeTypedefs}. # */ sub _getTypedefDetailString { my $self = shift; my $composite = shift; my @typedefObjs = $self->typedefs(); my $contentString; return $self->_getDetailString(\@typedefObjs, $composite, "DataTypes", "Typedefs"); # my @tempobjs = (); # if (!$self->unsorted()) { # @tempobjs = sort objName @typedefObjs; # } else { # @tempobjs = @typedefObjs; # } # foreach my $obj (@tempobjs) { # my $documentationBlock = $obj->documentationBlock($composite); # $contentString .= $documentationBlock; # } # return $contentString; } # /*! # @abstract # Returns the XML content string for typedefs in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getXMLPageString}. # */ sub _getTypedefXMLDetailString { my $self = shift; my @typedefObjs = $self->typedefs(); my $contentString; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @typedefObjs; } else { @tempobjs = @typedefObjs; } foreach my $obj (@tempobjs) { my $documentationBlock = $obj->XMLdocumentationBlock(); $contentString .= $documentationBlock; } return $contentString; } # /*! # @abstract # Writes the right-side content for structs in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link writeHeaderElements}. # */ sub writeStructs { my $self = shift; my $structsFile = $self->structsDir().$pathSeparator."Structs.html"; $self->_createHTMLOutputFile($structsFile, $self->_getStructDetailString(0), "Structs", 0); } # /*! # @abstract # Returns the right-side content for structs in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getCompositePageString} and {@link writeStructs}. # */ sub _getStructDetailString { my $self = shift; my $composite = shift; my @structObjs = $self->structs(); my $contentString; return $self->_getDetailString(\@structObjs, $composite, "structs", "Structs and Unions"); # my @tempobjs = (); # if (!$self->unsorted()) { # @tempobjs = sort objName @structObjs; # } else { # @tempobjs = @structObjs; # } # foreach my $obj (@tempobjs) { # my $documentationBlock = $obj->documentationBlock($composite); # $contentString .= $documentationBlock; # } # return $contentString; } # /*! # @abstract # Returns the XML content string for structs in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getXMLPageString}. # */ sub _getStructXMLDetailString { my $self = shift; my @structObjs = $self->structs(); my $contentString; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @structObjs; } else { @tempobjs = @structObjs; } foreach my $obj (@tempobjs) { my $documentationBlock = $obj->XMLdocumentationBlock(); $contentString .= $documentationBlock; } return $contentString; } # /*! # @abstract # Writes the right-side content for variables in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link writeHeaderElements}. # */ sub writeVars { my $self = shift; my $class = ref($self) || $self; my $globalname = "Globals"; if ($class ne "HeaderDoc::Header") { $globalname = "Member Data"; } my $varsFile = $self->varsDir().$pathSeparator."Vars.html"; $self->_createHTMLOutputFile($varsFile, $self->_getVarDetailString(0), "$globalname", 0); } # /*! # @abstract # Writes the right-side content for properties in this class. # @param self # The APIOwner object. # @discussion # Called by {@link writeHeaderElements}. # */ sub writeProps { my $self = shift; my $propsFile = $self->propsDir().$pathSeparator."Properties.html"; $self->_createHTMLOutputFile($propsFile, $self->_getPropDetailString(0), "Properties", 0); } # /*! # @abstract # Returns the right-side content for properties in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getCompositePageString} and {@link writeProps}. # */ sub _getPropDetailString { my $self = shift; my $composite = shift; my @propObjs = $self->props(); return $self->_getDetailString(\@propObjs, $composite, "props", "Properties"); } # /*! # @abstract # Returns the right-side content for variables in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getCompositePageString} and {@link writeVars}. # */ sub _getVarDetailString { my $self = shift; my $composite = shift; my @varObjs = $self->vars(); my $globalname = "Globals"; my $class = ref($self) || $self; if ($class ne "HeaderDoc::Header") { $globalname = "Member Data"; } return $self->_getDetailString(\@varObjs, $composite, "vars", $globalname); # my $contentString; # my @tempobjs = (); # if (!$self->unsorted()) { # @tempobjs = sort objName @varObjs; # } else { # @tempobjs = @varObjs; # } # foreach my $obj (@tempobjs) { # my $documentationBlock = $obj->documentationBlock($composite); # $contentString .= $documentationBlock; # } # return $contentString; } # /*! # @abstract # Returns the XML content string for properties in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getXMLPageString}. # */ sub _getPropXMLDetailString { my $self = shift; my @propObjs = $self->props(); my $contentString; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @propObjs; } else { @tempobjs = @propObjs; } foreach my $obj (@tempobjs) { my $documentationBlock = $obj->XMLdocumentationBlock(); $contentString .= $documentationBlock; } return $contentString; } # /*! # @abstract # Returns the XML content string for variables in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getXMLPageString}. # */ sub _getVarXMLDetailString { my $self = shift; my @varObjs = $self->vars(); my $contentString; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @varObjs; } else { @tempobjs = @varObjs; } foreach my $obj (@tempobjs) { my $documentationBlock = $obj->XMLdocumentationBlock(); $contentString .= $documentationBlock; } return $contentString; } # /*! # @abstract # Writes the right-side content for enums in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link writeHeaderElements}. # */ sub writeEnums { my $self = shift; my $enumsFile = $self->enumsDir().$pathSeparator."Enums.html"; $self->_createHTMLOutputFile($enumsFile, $self->_getEnumDetailString(0), "Enumerations", 0); } # /*! # @abstract # Returns the right-side content for enums in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getCompositePageString} and {@link writeEnums}. # */ sub _getEnumDetailString { my $self = shift; my $composite = shift; my @enumObjs = $self->enums(); my $contentString; return $self->_getDetailString(\@enumObjs, $composite, "enums", "Enumerated Types"); # my @tempobjs = (); # if (!$self->unsorted()) { # @tempobjs = sort objName @enumObjs; # } else { # @tempobjs = @enumObjs; # } # foreach my $obj (@tempobjs) { # my $documentationBlock = $obj->documentationBlock($composite); # $contentString .= $documentationBlock; # } # return $contentString; } # /*! # @abstract # Returns the XML content string for enums in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getXMLPageString}. # */ sub _getEnumXMLDetailString { my $self = shift; my @enumObjs = $self->enums(); my $contentString; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @enumObjs; } else { @tempobjs = @enumObjs; } foreach my $obj (@tempobjs) { my $documentationBlock = $obj->XMLdocumentationBlock(); $contentString .= $documentationBlock; } return $contentString; } # /*! # @abstract # Writes the right-side content for #define macros in # this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link writeHeaderElements}. # */ sub writePDefines { my $self = shift; my $pDefinesFile = $self->pDefinesDir().$pathSeparator."PDefines.html"; $self->_createHTMLOutputFile($pDefinesFile, $self->_getPDefineDetailString(0), "#defines", 0); } # /*! # @abstract # Returns the right-side content for #define macros in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getCompositePageString} and {@link writePDefines}. # */ sub _getPDefineDetailString { my $self = shift; my $composite = shift; my @ALLpDefineObjs = $self->pDefines(); my $contentString; my @pDefineObjs = (); foreach my $define (@ALLpDefineObjs) { if (!$define->parseOnly()) { push(@pDefineObjs, $define); } } return $self->_getDetailString(\@pDefineObjs, $composite, "PDefines", "Macro Definitions"); } # /*! # @abstract # Returns the right-side content for an array of objects. # @param self # The APIOwner object. # @param arrayref # A reference to the array of objects. # @param composite # Pass 1 if this is being generated for a composite page, else 0. # @param type # The raw name of the type (e.g. Enums, Functions). Used to generate # the filename for linking purposes. # @param displaytype # The human-readable name of the type. Used in headings. # */ sub _getDetailString { my $self = shift; my $arrayref = shift; my $composite = shift; my $type = shift; my $displaytype = shift; my @objs = @{$arrayref}; my $contentString = ""; my $count = @objs; if (!$count) { return ""; } my @tempobjs; if (!$self->unsorted()) { @tempobjs = sort objName @objs; } else { @tempobjs = @objs; } # print STDERR "TYPE: $type DISPLAYTYPE: $displaytype\n"; $contentString .= $self->_getEmbeddedTOC(\@tempobjs, ucfirst($type).".html", $type, $displaytype, $composite, 2); my %groups = ( "" => "" ); if ($HeaderDoc::groupright) { foreach my $obj (@objs) { my $group = $obj->group(); if (length($group)) { # print STDERR "GROUP $group\n"; $groups{$group} = $group; } } } foreach my $group (keys %groups) { # print STDERR "PRINTGROUP: $group\n"; if ($HeaderDoc::groupright) { my $show = 1; my $tempgroup = $group; if (!length($group)) { $tempgroup = "Untagged"; $show = 0; } $contentString .= "\n"; $contentString .= "

    $tempgroup $displaytype

    \n"; $contentString .= "
    \n"; } my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @objs; } else { @tempobjs = @objs; } foreach my $obj (@tempobjs) { if (!$HeaderDoc::groupright || ($obj->group() eq $group)) { my $documentationBlock = $obj->documentationBlock($composite); $contentString .= $documentationBlock; # } else { # print STDERR "NOMATCH: ".$obj->group()." != ".$group.".\n"; } } if ($HeaderDoc::groupright) { $contentString .= "
    \n"; } } return $contentString; } # /*! # @abstract # Returns the XML content string for #define macros in this class or header. # @param self # The APIOwner object. # @discussion # Called by {@link _getXMLPageString}. # */ sub _getPDefineXMLDetailString { my $self = shift; my @pDefineObjs = $self->pDefines(); my $contentString; my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @pDefineObjs; } else { @tempobjs = @pDefineObjs; } foreach my $obj (@tempobjs) { # print STDERR "OBJ: $obj: ".$obj->isBlock()."\n"; my $documentationBlock = $obj->XMLdocumentationBlock(); $contentString .= $documentationBlock; } return $contentString; } # /*! # @abstract # Writes the right-side content for classes in this header (or class). # @param self # The APIOwner object. # @discussion # Called by {@link writeHeaderElements}. # */ sub writeClasses { my $self = shift; my @classObjs = $self->classes(); my $classRootDir = $self->classesDir(); my @tempobjs = (); if (!$self->unsorted()) { @tempobjs = sort objName @classObjs; } else { @tempobjs = @classObjs; } foreach my $obj (@tempobjs) { my $className = $obj->name(); # for now, always shorten long names since some files may be moved to a Mac for browsing if (1 || $isMacOS) {$className = &safeName(filename => $className);}; my $classclass = ref($obj) || $obj; if ($classclass eq "HeaderDoc::CPPClass") { # Don't do this for Objective-C. Methods aren't # like functions. $obj->fixupTypeRequests(); } $obj->outputDir("$classRootDir$pathSeparator$className"); $obj->createFramesetFile(); $obj->createTOCFile(); $obj->writeHeaderElements(); $obj->writeHeaderElementsToCompositePage(); $obj->createContentFile() if (!$HeaderDoc::ClassAsComposite); } } # /*! # @abstract # Creates a file for XML output. # @param self # The APIOwner object. # @param outputFile # The output filename. # @param orig_fileString # The data to write to the file. # @param heading # The source or header filename. # */ sub _createXMLOutputFile { my $self = shift; my $class = ref($self); # my $copyrightOwner = $self->htmlToXML($class->copyrightOwner()); my $outputFile = shift; my $orig_fileString = shift; my $heading = shift; my $fullpath = $self->fullpath(); # if ($class eq "HeaderDoc::Header") { # my $headercopyright = $self->htmlToXML($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); if ($self->use_stdout()) { open(OUTFILE, ">&STDOUT"); } else { open(OUTFILE, ">$outputFile") || die "Can't write $outputFile.\n"; } if ($^O =~ /MacOS/io) {MacPerl::SetFileInfo('MSIE', 'TEXT', "$outputFile");}; my $encoding = $self->encoding(); # For some reason, some XML parser libraries (Perl's) can't # handle "utf8". (Libxml thinks it's just fine.) if ($encoding eq "utf8") { $encoding = "UTF-8"; } print OUTFILE "\n"; my $doctype = "header"; if ($self->isFramework()) { $doctype = "framework"; } # print OUTFILE "\n"; 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; } # /*! # @abstract # Creates a file for HTML output. # @param self # The APIOwner object. # @param outputFile # The output filename. # @param orig_fileString # The data to write to the file. # @param heading # The source or header filename. # @param includeDocNavComment # Specifies whether to include a doc navigator # comment in iframe output mode. # */ sub _createHTMLOutputFile { my $self = shift; my $class = ref($self); my $copyrightOwner = $class->copyrightOwner(); my $outputFile = shift; my $orig_fileString = shift; my $heading = shift; my $includeDocNavComment = shift; my $newTOC = $HeaderDoc::newTOC; 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/io) {MacPerl::SetFileInfo('MSIE', 'TEXT', "$outputFile");}; print OUTFILE "\n"; print OUTFILE ""; print OUTFILE "\n $heading\n $HTMLmeta \n\n"; if ($HeaderDoc::use_iframes || $HeaderDoc::newTOC == 5) { if (!$HeaderDoc::suppressDefaultStyles) { print OUTFILE $self->styleSheet(1); print OUTFILE "\n"; if ($HeaderDoc::newTOC == 5) { print OUTFILE "\n"; } } if (!$HeaderDoc::suppressDefaultJavaScript) { if ($HeaderDoc::newTOC == 5) { print OUTFILE "\n"; } if ($newTOC && $newTOC != 5) { # if (!$HeaderDoc::use_iframes) { print OUTFILE "\n"; } print OUTFILE "\n"; # if ($HeaderDoc::enable_custom_references) { # print OUTFILE "\n"; # } if ($newTOC == 2 || $newTOC == 3) { my $squoname = $self->name(); $squoname =~ s/'/'+"'"+'/sg; if ($newTOC == 3) { print OUTFILE "\n"; print OUTFILE "\n"; print OUTFILE "\n"; } print OUTFILE " \n"; print OUTFILE " \n"; print OUTFILE " \n"; print OUTFILE " \n"; print OUTFILE " \n"; if ($newTOC == 2) { print OUTFILE " \n"; } print OUTFILE " \n"; print OUTFILE " \n"; print OUTFILE " \n"; print OUTFILE " \n"; } } else { print OUTFILE "\n"; } } } print OUTFILE $self->styleSheet(0); my $onload = ""; if ($HeaderDoc::use_iframes) { if ($newTOC == 1) { $onload = "onload=\"initialize_page();\""; } elsif ((!$newTOC) || $newTOC == 5) { $onload = "onload=\"hidetoc();\""; } } my $style = ""; if ($HeaderDoc::newTOC == 2 || $HeaderDoc::newTOC == 3) { $style = "class=\"hasjs\""; $onload = "onload=\"delete_styles();\""; } print OUTFILE "\n"; if ($HeaderDoc::use_iframes && $includeDocNavComment) { # print OUTFILE "
    \n"; my $docNavigatorComment = $self->docNavigatorComment(); print OUTFILE $docNavigatorComment; } my $tocString = ""; if ($newTOC == 2 || $newTOC == 3) { $tocString = $self->tocString($newTOC); # When modifying this variable, remember to quote any dollar signs. # Also add nextLink and previousLink, e.g. # # my $heading = ""; if ($newTOC == 2) { $heading .= <
    Mac OS X Reference Library Apple Developer Connection spyglass button
    FOO ; } else { $heading .= < FOO ; } $heading .= <