#! /usr/bin/perl # # Class name: Function # Synopsis: Holds function info parsed by headerDoc # # Author: Matt Morse (matt@apple.com) # Last Updated: $Date: 2004/02/05 07:01:48 $ # # Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved. # # @APPLE_LICENSE_HEADER_START@ # # This file contains Original Code and/or Modifications of Original Code # as defined in and that are subject to the Apple Public Source License # Version 2.0 (the 'License'). You may not use this file except in # compliance with the License. Please obtain a copy of the License at # http://www.opensource.apple.com/apsl/ and read it before using this # file. # # The Original Code and all software distributed under the License are # distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER # EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, # INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. # Please see the License for the specific language governing rights and # limitations under the License. # # @APPLE_LICENSE_HEADER_END@ # ###################################################################### package HeaderDoc::Function; use HeaderDoc::Utilities qw(findRelativePath safeName getAPINameAndDisc printArray printHash); use HeaderDoc::HeaderElement; use HeaderDoc::MinorAPIElement; use HeaderDoc::APIOwner; @ISA = qw( HeaderDoc::HeaderElement ); use vars qw($VERSION @ISA); $VERSION = '1.20'; use strict; sub new { my($param) = shift; my($class) = ref($param) || $param; my $self = {}; bless($self, $class); $self->_initialize(); return($self); } sub _initialize { my($self) = shift; $self->SUPER::_initialize(); $self->{RESULT} = undef; $self->{CONFLICT} = 0; } sub clone { my $self = shift; my $clone = undef; if (@_) { $clone = shift; } else { $clone = HeaderDoc::Function->new(); } $self->SUPER::clone($clone); # now clone stuff specific to function $clone->{RESULT} = $self->{RESULT}; $clone->{CONFLICT} = $self->{CONFLICT}; return $clone; } sub result { my $self = shift; if (@_) { $self->{RESULT} = shift; } return $self->{RESULT}; } sub processFunctionComment { my $self = shift; my $fieldArrayRef = shift; my @fields = @$fieldArrayRef; foreach my $field (@fields) { SWITCH: { ($field =~ /^\/\*\!/)&& do {last SWITCH;}; # ignore opening /*! ($field =~ s/^method(\s+)/$1/) && do { my ($name, $disc); ($name, $disc) = &getAPINameAndDisc($field); $self->name($name); if (length($disc)) {$self->discussion($disc);}; last SWITCH; }; ($field =~ s/^function(\s+)/$1/) && do { my ($name, $disc); ($name, $disc) = &getAPINameAndDisc($field); $self->name($name); if (length($disc)) {$self->discussion($disc);}; last SWITCH; }; ($field =~ s/^serialData\s+//i) && do {$self->attribute("Serial Data", $field, 1); last SWITCH;}; ($field =~ s/^abstract\s+//) && do {$self->abstract($field); last SWITCH;}; ($field =~ s/^throws\s+//) && do {$self->throws($field); last SWITCH;}; ($field =~ s/^exception\s+//) && do {$self->throws($field); last SWITCH;}; ($field =~ s/^availability\s+//) && do {$self->availability($field); last SWITCH;}; ($field =~ s/^since\s+//) && do {$self->availability($field); last SWITCH;}; ($field =~ s/^author\s+//) && do {$self->attribute("Author", $field, 0); last SWITCH;}; ($field =~ s/^version\s+//) && do {$self->attribute("Version", $field, 0); last SWITCH;}; ($field =~ s/^deprecated\s+//) && do {$self->attribute("Deprecated", $field, 0); last SWITCH;}; ($field =~ s/^updated\s+//) && do {$self->updated($field); last SWITCH;}; ($field =~ /^see(also|)\s+/) && do { $self->see($field); last SWITCH; }; ($field =~ s/^discussion\s+//) && do {$self->discussion($field); last SWITCH;}; ($field =~ s/^templatefield\s+//) && do { $self->attributelist("Template Field", $field); last SWITCH; }; ($field =~ s/^param\s+//) && do { $field =~ s/^\s+|\s+$//g; # trim leading and trailing whitespace # $field =~ /(\w*)\s*(.*)/s; $field =~ /(\S*)\s*(.*)/s; my $pName = $1; my $pDesc = $2; my $param = HeaderDoc::MinorAPIElement->new(); $param->outputformat($self->outputformat); $param->name($pName); $param->discussion($pDesc); $self->addTaggedParameter($param); last SWITCH; }; ($field =~ s/^return\s+//) && do {$self->result($field); last SWITCH;}; ($field =~ s/^result\s+//) && do {$self->result($field); last SWITCH;}; # my $filename = $HeaderDoc::headerObject->filename(); my $filename = $self->filename(); my $linenum = $self->linenum(); print "$filename:$linenum:Unknown field in Function comment: $field\n"; } } } # Yikes! This shouldn't be here! # # sub getAPINameAndDisc { # my $line = shift; # my ($name, $disc, $operator); # # first, get rid of leading space # $line =~ s/^\s+//; # ($name, $disc) = split (/\s/, $line, 2); # if ($name =~ /operator/) { # this is for operator overloading in C++ # ($operator, $name, $disc) = split (/\s/, $line, 3); # $name = $operator." ".$name; # } # return ($name, $disc); # } sub setFunctionDeclaration { my $self = shift; my ($dec) = @_; my ($retval); my $localDebug = 0; my $noparens = 0; print "============================================================================\n" if ($localDebug); print "Raw declaration is: $dec\n" if ($localDebug); $self->declaration($dec); $self->declarationInHTML($dec); return $dec; # Throw all this away. #catch the case where this is a function-like macro if ($dec =~/^#define/) { # remove braced part $dec =~ s/(#define\s+\w+\s*\(.*\))\s+\{.*?\}\s*$/$1/sg; print "returning #define macro with declaration |$dec|\n" if ($localDebug); if ($self->outputformat() eq "html") { $dec =~ s/\\\n/\\
 /g; $self->declarationInHTML("$dec
"); return"$dec
\n"; } elsif (self->outputformat() eq "hdxml") { return"$dec"; } else { print "ERROR: UNKNOWN OUTPUT FORMAT!\n"; } } # regularize whitespace $dec =~ s/^\s+(.*)/$1/; # remove leading whitespace $dec =~ s/ \t/ /g; $dec =~ s//>/g; # remove return from parens of EXTERN_API(_C)(retval) if ($dec =~ /^EXTERN_API(_C)?/) { $dec =~ s/^EXTERN_API(_C)?\(([^)]+)\)(.*)/$2 $3/; $dec =~ s/^\s+//; } # remove CF_EXPORT and find return value $dec =~ s/^CF_EXPORT\s+(.*)/$1/; # print " with CF_EXPORT removed: $dec\n" if ($localDebug); my $parenscheck = $dec; $parenscheck =~ s/\s//smg; $parenscheck =~ s/^[-+]//smg; $parenscheck =~ s/^\(.*?\)//smg; if ($parenscheck !~ /\(/) { print "noparens\n" if ($localDebug);; $noparens = 1; } else { print "PC: $parenscheck\n" if ($localDebug);; } my $preOpeningParen = $dec; $preOpeningParen =~ s/^\s+(.*)/$1/; # remove leading whitespace $preOpeningParen =~ s/(\w[^(]+)\(([^)]*)\)(.*;[^;]*)$/$1/s; my $withinParens = $2; my $postParens = $3; # print "-->|$preOpeningParen|\n" if ($localDebug); my @preParenParts = split ('\s+', $preOpeningParen); my $funcName = pop @preParenParts; my $return = join (' ', @preParenParts); my $remainder = $withinParens; my @parensElements = split(/,/, $remainder); # now get parameters my $longstring = ""; my $position = 1; foreach my $element (@parensElements) { $element =~ s/\n/ /g; $element =~ s/^\s+//; print "element->|$element|\n" if ($localDebug); my @paramElements = split(/\s+/, $element); my $paramName = pop @paramElements; my $type = join (" ", @paramElements); #test for pointer asterisks and move to type portion of parameter declaration if ($paramName =~ /^\*/) { $paramName =~ s/^(\*+)(\w+)/$2/; $type .= " $1"; } if ($paramName ne "void") { # some programmers write myFunc(void) my $param = HeaderDoc::MinorAPIElement->new(); $param->outputformat($self->outputformat); $param->name($paramName); $param->position($position); $param->type($type); $self->addParsedParameter($param); } $position++; # print "element \"$element\"."; $element =~s/^\s*//; $element =~s/\s+/ /g; $element =~s/\s*$//; if ($longstring eq "") { $longstring = "\n    $element"; } else { $longstring = "$longstring,\n    $element"; } } if ($postParens =~ /\(.*\)\s*;/smg) { my $longstringb; my $position; my $pointerparms = $postParens; $pointerparms =~ s/^\s*\(//; $pointerparms =~ s/\)\s*;\s*$//; my @parensElements = split(/,/, $pointerparms); foreach my $element (@parensElements) { $element =~ s/\n/ /g; $element =~ s/^\s+//; print "element->|$element|\n" if ($localDebug); my @paramElements = split(/\s+/, $element); my $paramName = pop @paramElements; my $type = join (" ", @paramElements); #test for pointer asterisks and move to type portion of parameter declaration if ($paramName =~ /^\*/) { $paramName =~ s/^(\*+)(\w+)/$2/; $type .= " $1"; } if ($paramName ne "void") { # some programmers write myFunc(void) my $param = HeaderDoc::MinorAPIElement->new(); $param->outputformat($self->outputformat); $param->name($paramName); $param->position($position); $param->type($type); $self->addParsedParameter($param); } $position++; $element =~s/^\s*//; $element =~s/\s+/ /g; $element =~s/\s*$//; if ($longstringb eq "") { $longstringb = " (\n    $element"; } else { $longstringb = "$longstringb,\n    $element"; } } $longstringb .= "\n);\n"; $postParens = $longstringb; } if (!($return eq "")) { $return .= " "; } if ($noparens) { $retval = "$return$funcName $postParens
\n"; } else { if ($remainder =~/^\s*$/ || $remainder =~/^\s*void\s*$/) { $retval = "$return$funcName (void)$postParens
\n"; } else { $retval = "$return$funcName ($longstring\n)$postParens
\n"; } } print "Function: $funcName -- returning declaration:\n\t|$retval|\n" if ($localDebug); print "============================================================================\n" if ($localDebug); my $origdec = $self->declaration(); $retval = $origdec; $self->declarationInHTML($retval); return $retval; } sub XMLdocumentationBlock { my $self = shift; my $contentString; my $name = $self->name(); my $desc = $self->discussion(); my $throws = $self->XMLthrows(); my $abstract = $self->abstract(); my $availability = $self->availability(); my $updated = $self->updated(); my $declaration = $self->declarationInHTML(); my @parsedparams = $self->parsedParameters(); my @params = $self->taggedParameters(); my $returntype = $self->returntype(); my $result = $self->result(); my $group = $self->group(); my $attlists = $self->getAttributeLists(); my $atts = $self->getAttributes(); # my $apiUIDPrefix = HeaderDoc::APIOwner->apiUIDPrefix(); my $functype = "func"; if ($self->isTemplate()) { $functype = "ftmplt"; } my $uid = $self->apiuid($functype); # "//$apiUIDPrefix/c/func/$name"; # registerUID($uid); $contentString .= "\n"; # apple_ref marker $contentString .= "$name\n"; if (length($availability)) { $contentString .= "$availability\n"; } if (length($updated)) { $contentString .= "$updated\n"; } if (length($group)) { $contentString .= "$group\n"; } if (length($abstract)) { $contentString .= "$abstract\n"; } if (length($throws)) { $contentString .= "$throws\n"; } $contentString .= "$declaration\n"; $contentString .= "$desc\n"; my $arrayLength = @params; if ($arrayLength > 0) { my $paramContentString; foreach my $element (@params) { my $pName = $element->name(); my $pDesc = $element->discussion(); if (length ($pName)) { $paramContentString .= "$pName$pDesc\n"; } } if (length ($paramContentString)){ $contentString .= "\n"; $contentString .= $paramContentString; $contentString .= "\n"; } } my $arrayLength = @parsedparams; if ($arrayLength > 0) { my $paramContentString; foreach my $element (@parsedparams) { my $pName = $element->name(); my $pType = $element->type(); $pType =~ s/\s*$//s; if ($pName =~ s/^\s*(\*+)\s*//s) { $pType .= " $1"; } $pType = $self->textToXML($pType); $pName = $self->textToXML($pName); if (length ($pName) || length($pType)) { $paramContentString .= "$pType$pName\n"; } } if (length ($paramContentString)){ $contentString .= "\n"; $contentString .= $paramContentString; $contentString .= "\n"; } } if (length($atts)) { $contentString .= "$atts\n"; } if (length($attlists)) { $contentString .= "$attlists\n"; } if (length($returntype)) { $contentString .= "$returntype\n"; } if (length($result)) { $contentString .= "$result\n"; } $contentString .= "\n"; return $contentString; } sub conflict { my $self = shift; my $localDebug = 0; if (@_) { $self->{CONFLICT} = @_; } print "conflict $self->{CONFLICT}\n" if ($localDebug); return $self->{CONFLICT}; } sub printObject { my $self = shift; print "Function\n"; $self->SUPER::printObject(); print "Result: $self->{RESULT}\n"; } 1;