diff -r 000000000000 -r 638b9c697799 apicompatanamdw/compatanalysercmd/headeranalyser/src/PlatformData.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/apicompatanamdw/compatanalysercmd/headeranalyser/src/PlatformData.cpp Tue Jan 12 14:52:39 2010 +0530 @@ -0,0 +1,1401 @@ +/* +* Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +#include "CmdGlobals.h" +#ifdef __WIN__ +#pragma warning(disable:4786) +#endif + +#include +#include +#include "PlatformData.h" +#include "XMLUtils.h" +#include "XMLStringConst.h" +#include "Utils.h" +#include "BBCFileUtils.h" +#include "HAException.h" + + +const char* XML_FILE_ID_ATTRIBUTE = "id"; + +/** + * Generic utility function, which checks whether the given object is + * in the vector. + */ +template +inline bool IsObjectInVector(const vector& v, const C& o) +{ + return std::find(v.begin(), v.end(), o) != v.end(); +} + +// Convert to proper dir-separator +string& FixPathString(string& str) +{ + string::size_type dirSepInd = str.find_first_of("\\/"); + if( dirSepInd != string::npos && str.at(dirSepInd) != DIR_SEPARATOR ) + { + replaceChar(str, str.at(dirSepInd), DIR_SEPARATOR); + } + return str; +} + +/** + * + */ +ComponentFile::ComponentFile() +: +iComponent(0) +{} + +/** + * + */ +ComponentFile::ComponentFile(const string& ID, Component* comp) +: +iID(ID), +iComponent(comp) +{ } + +/** + * + */ +ComponentFile::ComponentFile(const ComponentFile &rhs) +: +iID(rhs.ID()), +iName(rhs.FileName()), +iPath(rhs.Path()), +iComponent(rhs.GetComponent()) +{ } + +/** + * + */ +ComponentFile::~ComponentFile() +{ } + +/** + * + */ +const string& ComponentFile::ID() const +{ + return iID; +} + +/** + * + */ +const string& ComponentFile::FileName() const +{ + return iName; +} + +/** + * + */ +const string& ComponentFile::Path() const +{ + return iPath; +} + +/** + * + */ +void ComponentFile::SetID(const string& ID) +{ + iID = ID; +} + +/** + * + */ +void ComponentFile::SetFileName(const string& name) +{ + iName = name; +} + +/** + * + */ +void ComponentFile::SetPath(const string& path) +{ + iPath = path; +} + +/** + * + */ +Component* ComponentFile::GetComponent() const +{ + return iComponent; +} + +/** + * + */ +void ComponentFile::SetComponent(Component* comp) +{ + iComponent = comp; +} + +/** + * + */ +string ComponentFile::ForcedInclude() +{ +return iForcedInclude; +} + +pair& ComponentFile::APIinfo() +{ + return iApiInfo; +} + +/** + * + */ +const ComponentFile& ComponentFile::operator= (const ComponentFile& rhs) +{ + if( &rhs != this ) + { + iID = rhs.ID(); + iName = rhs.FileName(); + iPath = rhs.Path(); + iComponent = rhs.GetComponent(); + } + return *this; +} + +/** + * + */ +bool ComponentFile::operator== (const ComponentFile& rhs) const +{ + return iID == rhs.ID() && +// iName == rhs.iName && +// iPath == rhs.iPath && + iComponent == iComponent; +} + +/** + * + */ +void ComponentFile::ProcessAttributes(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* node) +{ + // Read "fileid"-attribute: + const XMLCh* fileIdAttr = GetAttribute(node, XML_FILE_ID_ATTRIBUTE); + if( fileIdAttr ) + { + string str(toString(fileIdAttr)); + iID = FixPathString(toLower(str)); + } +} + +/** + * Reads child elements from the parsed XML (DOM) data. This baseclass implementation + * processes the "filename", "relativepath" and "include" elements, which are common + * to all component files. + */ +bool ComponentFile::ProcessChildElement(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* node, PlatformData* platform) +{ + if( node->getNodeType() != DOMNode::ELEMENT_NODE ) + return false; + + bool properChild = false; + + const XMLCh* elementtype = node->getNodeName(); + if( elementtype ) + { + string elemtypeStr(toString(elementtype)); + + //Handle the API info. + if( elemtypeStr == PLATFORM_ELEMENT_API_NAME ) + { + XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* apiNode = (DOMElement*)node; + char* apiname = _X( apiNode->getAttribute( _X( "name" ) ) ); + char* apiCategory = _X( apiNode->getAttribute( _X( "category" ) ) ); + + iApiInfo.first = apiname; + iApiInfo.second = apiCategory; + + _XX(apiname); + _XX(apiCategory); + } + if( elemtypeStr == PLATFORM_ELEMENT_INCLUDE ) + { + // Handle include element + const XMLCh* nodeVal = node->getTextContent(); + if( nodeVal ) + { + string tempStr(toString(nodeVal)); + iIncludes.push_back(FixPathString(toLower(tempStr))); + properChild = true; + } + } + else if( elemtypeStr == PLATFORM_ELEMENT_INCLUDEPATH ) + { + // Include paths: + const XMLCh* nodeVal = node->getTextContent(); + if( nodeVal ) + { + string tempStr(toString(nodeVal)); + iIncludePaths.push_back(FixPathString(toLower(tempStr))); + properChild = true; + } + } + else if( elemtypeStr == PLATFORM_ELEMENT_FORCEDINCLUDE ) + { + // Forced Include: + const XMLCh* nodeVal = node->getTextContent(); + if( nodeVal ) + { + iForcedInclude=toString(nodeVal); + properChild = true; + } + } + } + return properChild; +} + +/** + * + */ +const vector& ComponentFile::IncludePaths() const +{ + return iIncludePaths; +} + +/** + * + */ +void ComponentFile::AddIncludePath(const string& incPath) +{ + if( IsObjectInVector(iIncludePaths, incPath) == false ) + iIncludePaths.push_back(incPath); +} + +const vector& ComponentFile::Includes() const +{ + return iIncludes; +} + +void ComponentFile::AddInclude(const string& incHdr) +{ + if( IsObjectInVector(iIncludes, incHdr) == false ) + iIncludes.push_back(incHdr); +} + +void ComponentFile::SetIncludes(const vector& incs) +{ + iIncludes = incs; +} + +ParsedElement::ParsedElement() +{} + +ParsedElement::~ParsedElement() +{} + +/** + * Initializes the element using parsed XML (DOM) data. This method initiates + * attribute processing, child element processing and adds the element to + * the platform data object. + */ +bool ParsedElement::Initialize(DOMNode* node, PlatformData* platform) +{ + if( node == 0 || platform == 0 ) + return false; + + iRootDir = platform->GetRootDir(); + + // Read and process attributes of xml-element: + ProcessAttributes(node); + + // Process child elements: + DOMNodeList* childNodes = node->getChildNodes(); + XMLSize_t childListLen = 0; + if( childNodes ) + { + childListLen = childNodes->getLength(); + for( XMLSize_t cI = 0; cI < childListLen; ++cI ) + { + DOMNode* childNode = childNodes->item(cI); + if( childNode ) + { + ProcessChildElement(childNode, platform); + } + } + } + + // Add this element to a proper container of the platform data object: + return AddToPlatform(platform); +} + +/** + * + */ +Project::Project() +{} + +/** + * + */ +Project::Project(const string& prjID, Component* comp) +: ComponentFile(prjID, comp) +{ } + +/** + * + */ +Project::~Project() +{ } + +/** + * Adds this project element to platform's project list. + */ +bool Project::AddToPlatform(PlatformData* platform) +{ + return platform->AddProject(this); +} + +/** + * Processes the given child element. Project can have following + * child elements: + * - includepath + * - source + */ +bool Project::ProcessChildElement(DOMNode* child, PlatformData* platform) +{ + if( ComponentFile::ProcessChildElement(child, platform) == true ) + return true; + + bool properChild = false; + const XMLCh* childtype = child->getNodeName(); + if( childtype ) + { + string childtypeStr(toString(childtype)); + const XMLCh* nodeVal = child->getTextContent(); + if( nodeVal ) + { + if( childtypeStr == PLATFORM_ELEMENT_SOURCE ) + { + Source* srcObj = new Source(); + if( srcObj->Initialize(child, platform) ) + { + iSourceObjs.push_back(srcObj); + properChild = true; + } + else + delete srcObj; + } + } + } + return properChild; +} + +/** + * + */ +const FileList& Project::Sources() const +{ + return iSourceObjs; +} + +/** + * + */ +string Project::PrettyPrint(int indentSpaces) const +{ + string ret; + for( int i = 0; i < indentSpaces; ++i ) + { + ret += " "; + } + ret += string("Project ID: ") + iID + "\n"; + for( int i = 0; i < indentSpaces; ++i ) + { + ret += " "; + } + ret += "Sources:\n"; + for( FileList::const_iterator s = iSourceObjs.begin(); s != iSourceObjs.end(); ++s ) + { + ret += (*s)->PrettyPrint(indentSpaces+2); + } + return ret; +} + +/** + * Header + */ +Header::Header() +: +iCachedIncludes(0), +iCachedIncludePaths(0), +iCachedForcedInclude("") +{} +/** + * + */ +Header::Header(const string& hdrID, Component* comp) +: +ComponentFile(hdrID, comp), +iCachedIncludes(0), +iCachedIncludePaths(0), +iCachedForcedInclude("") +{ } + +/** + * + */ +Header::~Header() +{ + delete iCachedIncludes; + delete iCachedIncludePaths; +} + +/** + * + */ +Header::STATUS Header::Status() const +{ + return iStatus; +} + +/** + * + */ +void Header::SetStatus(Header::STATUS s) +{ + iStatus = s; +} + +/** + * + */ +bool Header::AddToPlatform(PlatformData* platform) +{ + return platform->AddHeader(this); +} + +/** + * + */ +string Header::PrettyPrint(int indentSpaces) const +{ + string ret; + for( int i = 0; i < indentSpaces; ++i ) + { + ret += " "; + } + ret += string("Header ID: ") + iID + "\n"; + + return ret; +} + +void Header::ProcessAttributes(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* node) +{ + /** + * Header element uses absolute path as a key, since that way it is easier + * to map this element to the filenames used in Analyser. Absolute path + * is calculated merging the root directories given in parameters (i.e BASELINEDIR + * and CURRENTDIR). + */ + const XMLCh* fileIdAttr = GetAttribute(node, XML_FILE_ID_ATTRIBUTE); + if( fileIdAttr ) + { + string tempStr(toString(fileIdAttr)); + FixPathString(toLower(tempStr)); + // Merge root and element directories. + // START -- Support for multiple header directories -- + list > fullID = BBCFileUtils::MergeDirs(iRootDir, tempStr); + list >::iterator fulliterbegin = fullID.begin(); + for(; fulliterbegin != fullID.end(); fulliterbegin++) + { + if( fulliterbegin->second ) + { + iID = fulliterbegin->first; + } + } + // END -- Support for multiple header directories -- + } +} + +/** + * When IncludesForHeader() method of PlatformData is called, PlatformData + * retrieves the additional include directives from all the sources in the + * component and caches the include directives to Header object, so next + * time the retrival is faster. + */ + +/** + * + */ +const vector* Header::CachedIncludes() const +{ + return iCachedIncludes; +} + +/** + * + */ +void Header::SetCachedIncludes(vector* incs) +{ + if( iCachedIncludes ) + delete iCachedIncludes; + iCachedIncludes = incs; +} + +/** + * When IncludesPathsForHeader() method of PlatformData is called, PlatformData + * retrieves the include paths from all the projects in the component and + * caches the include paths to Header object, so next time the retrival is + * faster. + */ + +/** + * + */ +const vector* Header::CachedIncludePaths() const +{ + return iCachedIncludePaths; +} + +/** + * + */ +void Header::SetCachedIncludePaths(vector* incPaths) +{ + if( iCachedIncludePaths ) + delete iCachedIncludePaths; + iCachedIncludePaths = incPaths; +} + + +/** + * When IncludesForHeader() method of PlatformData is called, PlatformData + * retrieves the additional forced include directive from the component + * and caches the forced include directive to Header object, so next + * time the retrival is faster. + */ + +/** + * + */ +string Header::CachedForcedInclude() const +{ + return iCachedForcedInclude; +} + +string Header::CachedSource() const +{ + return iCacheSrcObj; +} + +/** + * + */ +void Header::SetCachedForcedInclude(string finc) +{ + iCachedForcedInclude = finc; +} + +void Header::SetCachedSourceFile (string srcObj) +{ + iCacheSrcObj = srcObj; +} +/** + * Source + */ +Source::Source() +{} + +/** + * + */ +Source::Source(const string& srcID, Component* comp) +: ComponentFile(srcID, comp) +{ } + +/** + * + */ +Source::~Source() +{ } + +/** + * + */ +bool Source::AddToPlatform(PlatformData* platform) +{ + return platform->AddSource(this); +} + +/** + * + */ +string Source::PrettyPrint(int indentSpaces) const +{ + string ret; + for( int i = 0; i < indentSpaces; ++i ) + { + ret += " "; + } + ret += string("Source ID: ") + iID + "\n"; + for( int i = 0; i < indentSpaces; ++i ) + { + ret += " "; + } + ret += "Include directives:\n"; + for( vector::const_iterator inc = iIncludes.begin(); inc != iIncludes.end(); ++inc ) + { + for( int i = 0; i < indentSpaces+2; ++i ) + { + ret += " "; + } + ret += *inc + "\n"; + } + + return ret; +} + +/** + * Component + */ +Component::Component() +{ } + +/** + * + */ +Component::Component(const string& compID, Component* comp) +: +ComponentFile(compID, comp) +{ } + +/** + * + */ +Component::~Component() +{ } + +/** + * + */ +const FileList& Component::Headers() const +{ + return iHeaders; +} + +/** + * + */ +FileList& Component::Headers() +{ + return iHeaders; +} + +/** + * + */ +const FileList& Component::Projects() const +{ + return iProjects; +} + +/** + * + */ +FileList& Component::Projects() +{ + return iProjects; +} + +/** + * + */ +void Component::AddHeader(ComponentFile* hdr) +{ + if( IsObjectInVector(iHeaders, hdr) == false ) + { + iHeaders.push_back(hdr); + } +} + +/** + * + */ +void Component::AddProject(ComponentFile* prj) +{ + if( IsObjectInVector(iProjects, prj) == false ) + { + iProjects.push_back(prj); + } +} + +/** + * Processes child elements. Component can have following child elements: + * - Header + * - Project reference + */ +bool Component::ProcessChildElement(DOMNode* child, PlatformData* platform) +{ + if( ComponentFile::ProcessChildElement(child, platform) == true ) + return true; + + bool properChild = false; + const XMLCh* childtype = child->getNodeName(); + if( childtype ) + { + string childtypeStr(toString(childtype)); + if( childtypeStr == PLATFORM_ELEMENT_HEADER ) + { + Header* hdr = new Header(); + string headerID(this->ID()); + if( hdr->Initialize(child, platform) ) + { + if(headerID == PLATFORM_IGNORED_COMPONENT ) + hdr->SetStatus(Header::HDR_STATUS_IGNORE); + + XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* hdrNode = (DOMElement*)child; + char* headername = _X( hdrNode->getAttribute( _X( "id" ) ) ); + string header (headername); + header = FixPathString(toLower(header)); + int loc = header.find_last_of(DIR_SEPARATOR); + if(loc != -1 ) + { + // store header file name and path from header id tag only. + hdr->SetFileName(header.substr(loc+1,string::npos)); + hdr->SetPath(header.substr(0,loc)); + } + _XX(headername); + + hdr->SetComponent(this); + iHeaders.push_back(hdr); + properChild = true; + } + else + { + delete hdr; + } + } + else if( childtypeStr == PLATFORM_ELEMENT_PROJECT ) + { + Project* prj = new Project(); + if (prj->Initialize(child, platform) ) + { + prj->SetComponent(this); + iProjects.push_back(prj); + properChild = true; + } + else + { + delete prj; + } + } + } + return properChild; +} + +/** + * + */ +bool Component::AddToPlatform(PlatformData* platform) +{ + return platform->AddComponent(this); +} + +/** + * + */ +string Component::PrettyPrint(int indentSpaces) const +{ + string ret; + for( int i = 0; i < indentSpaces; ++i ) + { + ret += " "; + } + ret += string("Component ID: ") + iID + "\n"; + for( int i = 0; i < indentSpaces; ++i ) + { + ret += " "; + } + ret += "Headers:\n"; + for( FileList::const_iterator h = iHeaders.begin(); h != iHeaders.end(); ++h ) + { + ret += (*h)->PrettyPrint(indentSpaces+2); + } + + for( int i = 0; i < indentSpaces; ++i ) + { + ret += " "; + } + ret += "Projects\n"; + + for( FileList::const_iterator p = iProjects.begin(); p != iProjects.end(); ++p ) + { + ret += (*p)->PrettyPrint(indentSpaces+2); + } + + return ret; +} + +/** + * PlatformData contains all the elements defined in the platrofm input file. + * It parses the XML-file and populates the internal containers. It also + * has different kind of methods for retrieving the data and the associations + * between elements. + */ +PlatformData::PlatformData(const string& pfVersion, const string& rootDir) +: +iDOMParser(0), +iDOMDoc(0), +iDOMRootElement(0), +iPfVersion(pfVersion), +iRootDir(rootDir) +{ } + +/** + * + */ +PlatformData::~PlatformData() +{ + if (iDOMParser != NULL) + { + iDOMParser->resetDocumentPool(); + iDOMParser->release(); + iDOMParser = NULL; + } + + CFileMap::iterator i; + + for( i = iHeadersById.begin(); i != iHeadersById.end(); ++i ) + { + delete i->second; + } + + for( i = iProjectsById.begin(); i != iProjectsById.end(); ++i ) + { + delete i->second; + } + + for( i = iSourcesById.begin(); i != iSourcesById.end(); ++i ) + { + delete i->second; + } + + for( ComponentList::iterator ic = iCList.begin(); ic != iCList.end(); ++ic ) + { + delete ic->second; + } +} + +/** + * + */ +void PlatformData::Initialize(const string& dataFileName) +{ + // First read and parse the XML-file: + int ret = 0; + if (iDOMParser != NULL) + { + iDOMParser->resetDocumentPool(); + iDOMParser->release(); + iDOMParser = 0; + } + cout << "Parsing platform data for " << iPfVersion << "..."; + try { + ret = ParseXMLFile(dataFileName, iDOMParser, iDOMDoc, iDOMRootElement); + } + catch (HAException&) + { + cout.flush(); + cerr.flush(); + cerr << "Failed!" << endl; + if( iDOMParser ) + { + iDOMParser->resetDocumentPool(); + iDOMParser->release(); + iDOMParser = 0; + } + throw; + } + cout << "Done." << endl; + + // Then traverse the DOM tree and populate the containers: + cout << "Initializing platform data for " << iPfVersion << "..."; + try { + InitializeElements(); + } + catch( HAException& ) + { + cerr << "Failed." << endl; + iDOMParser->resetDocumentPool(); + iDOMParser->release(); + iDOMParser = 0; + throw; + } + cout << "Done." << endl; + iDOMParser->resetDocumentPool(); + iDOMParser->release(); + iDOMParser = 0; + cout << "Platform " << iPfVersion << " successfully initialized from platform " << iVersionStr << " data!" << endl << endl; +} + +/** + * + */ +bool PlatformData::AddComponent(Component* comp) +{ + return iCList.insert(make_pair( comp->ID(), comp )).second; +} + +/** + * + */ +bool PlatformData::AddProject(Project* prj) +{ + if( iProjectsById.insert(make_pair(prj->ID(), prj)).second == false ) + return false; + + return true; +} + +/** + * + */ +bool PlatformData::AddSource(Source* src) +{ + if( iSourcesById.insert(make_pair(src->ID(), src)).second == false ) + return false; + + return true; +} + +/** + * + */ +bool PlatformData::AddHeader(Header* hdr) +{ + if( iHeadersById.insert(make_pair(hdr->ID(), hdr)).second == false ) + return false; + + return true; +} + +/** + * Factory method for creating element objects. + */ +ParsedElement* PlatformData::CreateElement( XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* node ) +{ + const string elementType( toString( node->getNodeName() )); + ParsedElement* elem = 0; + + if( elementType == PLATFORM_ELEMENT_COMPONENT ) + { + elem = new Component(); + } + else if( elementType == PLATFORM_ELEMENT_PROJECT ) + { + elem = new Project(); + } + else if( elementType == PLATFORM_ELEMENT_SOURCE ) + { + elem = new Source(); + } + + return elem; +} + +/** + * Traverses through the DOM-tree and builds element objects. + */ +void PlatformData::InitializeElements() +{ + if( iDOMDoc == 0 || iDOMRootElement == 0) + throw HAException(string("Platform ") + string(iPfVersion) + string(" initialization failed.\n")); + DOMNodeIterator* domIter = iDOMDoc->createNodeIterator(iDOMRootElement, DOMNodeFilter::SHOW_ELEMENT, NULL, true); + if( domIter == 0 ) + throw HAException(string("Platform ") + string(iPfVersion) + string(" initialization failed.\n")); + DOMNode* root = domIter->getRoot(); + if( root ) + { + const XMLCh* platformVersion = GetAttribute(root, KXMLPlatformVersion); + if( platformVersion ) + iVersionStr = toString(platformVersion); + } + DOMNode* nodeIter = 0; + ParsedElement* elem = 0; + while( (nodeIter = domIter->nextNode()) != 0 ) + { + elem = CreateElement(nodeIter); + if( elem && elem->Initialize(nodeIter, this) == false ) + { + delete elem; + } + } + + domIter->release(); +} + +/** + * + */ +const CFileMap& PlatformData::HeadersById() const +{ + return iHeadersById; +} + +/** + * + */ +const CFileMap& PlatformData::ProjectsById() const +{ + return iProjectsById; +} + +/** + * + */ +CFileMap& PlatformData::ProjectsById() +{ + return iProjectsById; +} + +/** + * + */ +const CFileMap& PlatformData::SourcesById() const +{ + return iSourcesById; +} + +/** + * Finds include paths defined in the projects belonging to the + * same component than the header. + */ +const vector& PlatformData::IncludePathsForHeader(const string& headerID) +{ + CFileMap::const_iterator hdrIter = iHeadersById.find(headerID); + if( hdrIter != iHeadersById.end() ) + { + Header* hdrObj = dynamic_cast(hdrIter->second); + if( hdrObj ) + return IncludePathsForHeader(hdrObj); + } + + return iDummyStringVector; +} + +/** + * Finds include paths defined in the projects belonging to the + * same component than the header. + */ +const vector& PlatformData::IncludePathsForHeader(Header* hdrObj) +{ + if( hdrObj == 0 ) + return iDummyStringVector; + + // First try to find includes from the cache: + const vector* cached = hdrObj->CachedIncludePaths(); + if( cached ) + { + return *cached; + } + + auto_ptr > newVector(new vector()); + Component* comp = 0; + + if( (comp = hdrObj->GetComponent()) != 0 ) + { + // First insert the include paths defined in component level: + newVector->insert(newVector->end(), comp->IncludePaths().begin(), comp->IncludePaths().end()); + + const FileList& prjs = comp->Projects(); + for( FileList::const_iterator prj = prjs.begin(); prj != prjs.end(); ++prj ) + { + Project* prjObj = dynamic_cast(*prj); + if( prjObj ) + { + const vector& iPaths = prjObj->IncludePaths(); + vector::const_iterator ip = iPaths.begin(); + + for( ; ip != iPaths.end(); ++ip ) + { + if( !IsObjectInVector(*newVector, *ip) ) + { + newVector->push_back(*ip); + } + } + } + } + } + + const vector& hdrIncs = hdrObj->IncludePaths(); + for( vector::const_iterator i = hdrIncs.begin(); i != hdrIncs.end(); ++i ) + { + if( !IsObjectInVector(*newVector, *i) ) + { + newVector->push_back(*i); + } + } + + // variable to track whether project has been found + bool found = false; + // Find a project in the platform data which includes the header under analysis and + // add all paths in the mmp file as dependencies before compilation. + for( CFileMap::const_iterator pIter = iProjectsById.begin(); pIter != iProjectsById.end() && !found; ++pIter ) + { + //First iterate over projects + Project* prj = dynamic_cast(pIter->second); + const FileList& src = prj->Sources(); + FileList::const_iterator sIter = src.begin(); + for(;sIter != src.end() && !found; ++sIter) + { + // then search each source include in individual projects + Source* so = dynamic_cast(*sIter); + const vector& inc = so->Includes(); + vector::const_iterator iIter = inc.begin(); + for(;iIter != inc.end() && !found; ++iIter) + { + string::size_type dirEnd = (*iIter).find_last_of('/\\'); + // IF header found + if( (dirEnd == string::npos && *iIter == hdrObj->FileName()) || + (dirEnd != string::npos && string((*iIter).begin()+dirEnd+1, (*iIter).end()) == hdrObj->FileName())) + { + const vector& tmp = prj->IncludePaths(); + if( IsObjectInVector(tmp, hdrObj->Path()) ) + { + vector::const_iterator str = tmp.begin(); + for(;str != prj->IncludePaths().end(); ++str) + { + // only include paths which are not already present + if( !IsObjectInVector(*newVector, *str) ) + { + newVector->insert(newVector->end(), *str); + found = true; + } + } + } + } + } + } + } + hdrObj->SetCachedIncludePaths(newVector.release()); + return *(hdrObj->CachedIncludePaths()); +} + +/** + * Finds include directives used with this header when the header + * is compiled. Algorithm finds the Header object using + * the given ID and then calls overloaded IncludesForHeader + * using the Header object. + */ +const vector& PlatformData::IncludesForHeader( const string& headerID ) +{ + CFileMap::const_iterator hdrIter = iHeadersById.find(headerID); + if( hdrIter != iHeadersById.end() ) + { + Header* hObj = dynamic_cast(hdrIter->second); + if( hObj ) + return IncludesForHeader(hObj); + } + return iDummyStringVector; +} + +void PlatformData::IncludesFromSource(const Header* hObj, const Source* srcObj, vector& includes) const +{ + const vector& includeDirectives = srcObj->Includes(); + vector::const_iterator inc = includeDirectives.begin(); + for( ; inc != includeDirectives.end(); ++inc ) + { + string::size_type dirEnd = (*inc).find_last_of("/\\"); + + if( (dirEnd == string::npos && *inc == hObj->FileName()) || + (dirEnd != string::npos && string(inc->begin()+dirEnd+1, inc->end()) == hObj->FileName())) + { + // The header was found. Take all the preceding include directives: + for( vector::const_iterator tempIt = includeDirectives.begin(); tempIt != inc; ++tempIt) + { + if( IsObjectInVector(includes, *tempIt) == false ) + { + includes.push_back(*tempIt); + } + } + break; + } + } +} + +/** + * Finds include directives used with this header when the header + * is compiled. Algorithm find first all the projects belonging + * to the same component than the given Header object. + * Then it finds all the source files belonging to the projects. + * Then it scans the source files and if a source file includes + * this header, all the preceding include directives in that source + * file are inserted to the result vector. + * + * An example: + * + * Header, id: epoc32/include/hdr1.h, belongs to component c, which + * contains one project p.mmp. Project p.mmp contains two source files: + * s1.cpp and s2.cpp. Source s1.cpp includes hdrX.h, hdrY.h and hdr1.h + * (in that order). Source s2.cpp does not include the hdr1.h at all. + * The returned headers in above example would be hdrX.h and hdrY.h. + */ +const vector& PlatformData::IncludesForHeader(Header* hObj, Header* baseHObj) +{ + string tempSpurceObj; + if( hObj == 0 ) + return iDummyStringVector; + + if( hObj->CachedIncludes() != 0 ) + return *(hObj->CachedIncludes()); + + + // Start build new include list: + auto_ptr > newVector(new vector()); + Component* comp = 0; + + if( (comp = hObj->GetComponent()) != 0 ) + { + //set the forced header for this header + hObj->SetCachedForcedInclude(comp->ForcedInclude()); + // Insert include directives defined in component level: + newVector->insert(newVector->end(), comp->Includes().begin(), comp->Includes().end()); + + // Then find all the sources that are including this header and get all the preceding include + // directives from the sources. The shortest list will do. + + const FileList& projects = comp->Projects(); // All the projects in this component + FileList::const_iterator fIter = projects.begin(); + + // Get needed source files from the projects of this component: + FileList srcObjs; + for( ; fIter != projects.end(); ++fIter ) + { + Project* prj = dynamic_cast(*fIter); + if( prj ) + { + srcObjs.insert(srcObjs.end(), prj->Sources().begin(), prj->Sources().end()); + } + } + + // Next we investigate the include directives of each source file + // and get all the headers that are included before the given + // header file. + auto_ptr > includesFromSrc(0); + for( FileList::iterator src = srcObjs.begin(); src != srcObjs.end(); ++src ) + { + Source* srcObj = dynamic_cast(*src); + if( srcObj == 0 ) + continue; + + const vector& includeDirectives = srcObj->Includes(); + vector::const_iterator inc = includeDirectives.begin(); + auto_ptr > tmpIncludes(new vector()); + + IncludesFromSource(hObj, srcObj, *tmpIncludes); + if( includesFromSrc.get() == 0 || + (tmpIncludes->size() > 0 && (tmpIncludes->size() < includesFromSrc->size() || includesFromSrc->size()==0) )) + { + tempSpurceObj = srcObj->ID(); + includesFromSrc = tmpIncludes; // Get the smallest possible set of additional includes. + } + } + if( includesFromSrc.get() ) + { + newVector->insert(newVector->end(), includesFromSrc->begin(), includesFromSrc->end()); + } + } + + if( newVector->size() == 0 ) + { + // No includes found. Let's try to find some source from other components. First one will do... + for( CFileMap::const_iterator s = iSourcesById.begin(); s != iSourcesById.end(); ++s ) + { + auto_ptr > tmpIncludes(new vector()); + Source* sO = dynamic_cast(s->second); + if( sO ) + { + IncludesFromSource(hObj, sO, *tmpIncludes); + if( tmpIncludes->size() > 0 ) + { + string curSrc; + string baseSrc; + if ( baseHObj != NULL) // IncludesForHeader() is called for current sdk + { + string::size_type loc = sO->ID().find_last_of('/\\'); + if(loc != string::npos ) + curSrc = sO->ID().substr(loc+1 , string::npos); + loc = string::npos; + loc = baseHObj->CachedSource().find_last_of('/\\'); + if(loc != string::npos) + baseSrc = baseHObj->CachedSource().substr(loc+1, string::npos); + } + // If the header is of baseline sdk or the current headers source file name is same as baseline's source file, + // In both of these cases , the dependent headers will be taken from platform data file + if(baseHObj == NULL || (baseSrc.size() > 0 && baseSrc == curSrc) ) + { + newVector->insert(newVector->end(), tmpIncludes->begin(), tmpIncludes->end()); + } + else // as current header's source file is not same as basiline's, so baseline's cacheinclude will be taken for current header too. + { + newVector->insert(newVector->end(), baseHObj->CachedIncludes()->begin(), baseHObj->CachedIncludes()->end()); + } + break; + } + } + } + } + hObj->SetCachedIncludes(newVector.release()); + if(baseHObj == NULL) // IncludesForHeader() is called for baseline sdk, so get the source file name in cache + { + hObj->SetCachedSourceFile(tempSpurceObj); + } + return *(hObj->CachedIncludes()); +} +/** + * + */ +string PlatformData::PrettyPrint() const +{ + string ret("PLATFORM version: "); + ret += iVersionStr + "\n"; + + for( ComponentList::const_iterator c = iCList.begin(); c != iCList.end(); ++c ) + { + ret += c->second->PrettyPrint(); + } + return ret; +} + +/** + * + */ +const ComponentList& PlatformData::Components() const +{ + return iCList; +} + +/** + * + */ +const string& PlatformData::GetRootDir() const +{ + return iRootDir; +}