Event hierarchy diagram code.

From IGSTK

Jump to: navigation, search

#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 )
Personal tools
TOOLBOX
LANGUAGES