From IGSTK
#include <string>
#include <algorithm>
#include <fstream>
#include <iostream>
#include <vector>
#include <set>
/** Description of an IGSTKEvent */
class EventDescription
{
public:
std::string m_ChildName;
std::string m_ParentName;
std::string m_PayloadName;
std::string m_FileName;
EventDescription() {}
};
/** Class that parses header files and generates .dot output
* for the IGSTK event hierarchy.
*/
class GraphCreator
{
public:
typedef std::string StringType;
typedef StringType::iterator StringIterator;
typedef EventDescription EventDescriptionType;
typedef std::vector<EventDescriptionType> EventDescriptionContainerType;
typedef long int PositionType;
typedef std::set< std::pair< StringType, StringType > > NodeSetType;
/** Remove whitespaces and colons (dot doesn't like colons). */
std::string CleanupString( std::string& input )
{
std::string outputString;
for (std::string::iterator siter = input.begin();
siter != input.end();
++siter)
{
const char thisChar = *siter;
if ( thisChar == '\t' || thisChar == '\n' || thisChar == ' ' || thisChar == ':' )
{
continue;
}
else
{
outputString.push_back( thisChar );
}
}
return outputString;
}
/** Parse the file and get IGSTK events */
bool BuildGraph()
{
const std::string eventToken = "EventMacro";
const PositionType hackOffset = 80;
const std::string defineToken = "define";
PositionType lastPos = m_Buffer.find( eventToken );
while ( lastPos != -1 )
{
// Check that this is not a macro definition.
std::string defineSubString = m_Buffer.substr( lastPos - hackOffset, hackOffset );
PositionType definePos = defineSubString.find( defineToken.c_str() );
if (definePos == -1 )
{
// Get child and parent names
PositionType childStart = m_Buffer.find( "(", lastPos ) + 1;
PositionType childEnd = m_Buffer.find( ",", childStart + 1 );
PositionType parentStart = childEnd + 1;
PositionType parentEnd = m_Buffer.find( ")", parentStart + 1);
std::string parentString = m_Buffer.substr( parentStart, parentEnd - parentStart);
// We need to check the parent description to see if we also
// got a payload
PositionType payloadStart = parentString.find( ",");
PositionType payloadEnd = 0;
if ( payloadStart != -1 )
{
payloadEnd = parentString.size() - 1;
parentEnd = payloadStart;
}
// Create a description and fill it in.
EventDescription eventDescription;
eventDescription.m_FileName = m_FileName;
eventDescription.m_ChildName = CleanupString( m_Buffer.substr( childStart, childEnd - childStart ) );
if ( payloadStart != -1 )
{
eventDescription.m_ParentName = CleanupString( parentString.substr( 0, payloadStart ) );
eventDescription.m_PayloadName = CleanupString( parentString.substr( payloadStart + 1, parentString.size() - 1 ) );
}
else
{
eventDescription.m_ParentName = CleanupString( parentString );
eventDescription.m_PayloadName = "None";
}
// Add the child event to the set of found nodes. The macro we are looking at contains
// the definition for the child event.
m_NodeSet.insert( std::pair< StringType, StringType >(eventDescription.m_ChildName, m_FileName) );
m_EventDescriptionContainer.push_back( eventDescription );
} // if definePos != -1
// Next event macro
lastPos = m_Buffer.find( eventToken, lastPos + 1 );
}
return true;
}
/** Set the buffer to parse. */
void SetBuffer( std::string buffer )
{
m_Buffer = buffer;
}
/** Split off the filename. */
std::string SplitFileName( std::string filename )
{
const char* fileNameToken = "/";
PositionType pos = filename.find_last_of(fileNameToken);
if (pos != -1)
{
std::string returnFileName = filename.substr( pos+1, filename.size() - 1 );
return returnFileName;
}
else
{
return filename;
}
}
/** Set the current filename so that we can report it. */
void SetFileName( std::string filename )
{
m_FileName = SplitFileName(filename);
}
/** Write the dot graph file. */
void WriteDotFile( const char* filename )
{
std::ofstream outputFile( filename );
outputFile << "digraph G { " << std::endl;
outputFile << "rankdir=RL" << std::endl;
/** Write out the set of nodes. */
for ( NodeSetType::iterator siter = m_NodeSet.begin();
siter != m_NodeSet.end();
++siter )
{
std::string labelString = " [label=\"";
labelString += (*siter).first;
labelString += "\\n";
labelString += (*siter).second;
labelString += "\" ];";
outputFile << (*siter).first << labelString << std::endl;
}
/** Write the edges. */
for ( EventDescriptionContainerType::iterator eiter = m_EventDescriptionContainer.begin();
eiter != m_EventDescriptionContainer.end();
++eiter)
{
outputFile << (*eiter).m_ChildName << " -> " << (*eiter).m_ParentName;
outputFile << ";" << std::endl;
}
outputFile << "}" << std::endl;
}
protected:
StringType m_Buffer;
StringType m_FileName;
NodeSetType m_NodeSet;
EventDescriptionContainerType m_EventDescriptionContainer;
};
int main( int argc, char* argv[] )
{
if (argc < 3 )
{
std::cout << "Usage : " << argv[0] << " dot_output_file input_file1 input_file2 ... input_fileN" << std::endl;
return EXIT_FAILURE;
}
const char* outputFileName = argv[1];
GraphCreator graphCreator;
while ( argc > 2 )
{
const char* filename = argv[ argc - 1 ];
std::ifstream file;
file.open( filename, std::ios::binary | std::ios::in);
if(!file.is_open())
{
std::cout << "Cannot open file: " << filename << std::endl;
continue;
}
else
{
std::cout << "Processing : " << filename << std::endl;
}
file.seekg(0,std::ios::end);
unsigned long fileSize = file.tellg();
file.seekg(0,std::ios::beg);
char* buf = new char[fileSize+1];
file.read(buf,fileSize);
buf[fileSize] = 0;
std::string buffer(buf);
buffer.resize(fileSize);
delete [] buf;
file.close();
graphCreator.SetFileName( filename );
graphCreator.SetBuffer( buffer );
graphCreator.BuildGraph();
--argc;
}
graphCreator.WriteDotFile( outputFileName );
std::cout << "Wrote dot file : " << outputFileName << std::endl;
return EXIT_SUCCESS;
}
Project( CreateEventGraph )
add_executable( CreateEventGraph CreateEventGraph.cxx )