]> Creatis software - cpPlugins.git/blobdiff - appli/bash/MOC.cxx
Moved to version 1.0
[cpPlugins.git] / appli / bash / MOC.cxx
diff --git a/appli/bash/MOC.cxx b/appli/bash/MOC.cxx
new file mode 100644 (file)
index 0000000..8052b05
--- /dev/null
@@ -0,0 +1,438 @@
+// =========================================================================
+// @author Leonardo Florez-Valencia (florez-l@javeriana.edu.co)
+// =========================================================================
+
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <queue>
+#include <set>
+#include <sstream>
+#include <streambuf>
+#include <string>
+#include <vector>
+
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/program_options.hpp>
+#include <boost/tokenizer.hpp>
+#include <mstch/mstch.hpp>
+
+// -------------------------------------------------------------------------
+typedef boost::filesystem::path TPath;
+typedef std::vector< std::string > TStrings;
+typedef std::map< std::string, TStrings > TDefinitions;
+struct TData
+{
+  TPath             Input;
+  TPath             Output;
+  std::set< TPath > IncludePaths;
+  TStrings          InputLines;
+  TStrings          CompleteLines;
+  TDefinitions      Definitions;
+};
+TData Data;
+
+// -------------------------------------------------------------------------
+bool Arguments( int argc, char* argv[] );
+bool Read( const std::string& input, std::string& buffer );
+bool Lines( const std::string& input, TStrings& lines );
+void Includes( TStrings& new_lines, const TStrings& lines );
+void Definitions( TDefinitions& defs, const TStrings& lines );
+int Parse( );
+void Render( std::ostream& out, const std::string& in, mstch::map& context );
+
+// -------------------------------------------------------------------------
+int main( int argc, char* argv[] )
+{
+  if( Arguments( argc, argv ) )
+  {
+    if( Lines( Data.Input.string( ), Data.InputLines ) )
+    {
+      Includes( Data.CompleteLines, Data.InputLines );
+      Definitions( Data.Definitions, Data.CompleteLines );
+      return( Parse( ) );
+    }
+    else
+      return( 1 );
+  }
+  else
+    return( 1 );
+}
+
+// -------------------------------------------------------------------------
+bool Arguments( int argc, char* argv[] )
+{
+  // Declare the supported options.
+  boost::program_options::options_description desc( "Allowed options" );
+  desc.add_options( )
+    ( "help,h", "produce help message" )
+    (
+      "input,i",
+      boost::program_options::value< std::string >( ),
+      "Input"
+      )
+    (
+      "output,o",
+      boost::program_options::value< std::string >( ),
+      "Output"
+      )
+    (
+      "include,I",
+      boost::program_options::value< TStrings >( ),
+      "Include directory(ies)"
+      )
+    ;
+
+  try
+  {
+    // Parse input arguments
+    boost::program_options::variables_map vm;
+    boost::program_options::store(
+      boost::program_options::parse_command_line( argc, argv, desc ), vm
+      );
+    boost::program_options::notify( vm );
+    if( vm.count( "help" ) )
+    {
+      std::cerr << desc << std::endl;
+      return( false );
+
+    } // fi
+    if( vm.count( "input" ) == 0 || vm.count( "output" ) == 0 )
+    {
+      std::cerr
+        << "Invalid usage: --input and --output are required."
+        << std::endl << desc << std::endl;
+      return( false );
+
+    } // fi
+
+    // Get values
+    Data.Input =
+      boost::filesystem::canonical(
+        TPath( vm[ "input" ].as< std::string >( ) )
+        );
+    Data.Output = TPath( vm[ "output" ].as< std::string >( ) );
+    Data.IncludePaths.clear( );
+    Data.IncludePaths.insert( Data.Input.parent_path( ) );
+    if( vm.count( "include" ) > 0 )
+      for( const std::string& dir: vm[ "include" ].as< TStrings >( ) )
+        Data.IncludePaths.insert( boost::filesystem::canonical( TPath( dir ) ) );
+    return( true );
+  }
+  catch( std::exception& err )
+  {
+    std::cerr << "Error caught: " << err.what( ) << std::endl;
+    std::cerr << desc << std::endl;
+    return( false );
+
+  } // yrt
+}
+
+// -------------------------------------------------------------------------
+bool Read( const std::string& input, std::string& buffer )
+{
+  std::ifstream in( input.c_str( ) );
+  if( !in )
+  {
+    std::cerr
+      << "===============================" << std::endl
+      << "Error caught: " << std::endl
+      << "could not load input file \"" << input << "\"" << std::endl
+      << "===============================" << std::endl
+      << std::endl;
+    return( false );
+
+  } // fi
+  typedef std::istreambuf_iterator< char > _TDIt;
+  std::istringstream str( std::string( ( _TDIt( in ) ), _TDIt( ) ) );
+  buffer = str.str( );
+  in.close( );
+  return( true );
+}
+
+// -------------------------------------------------------------------------
+bool Lines( const std::string& input, TStrings& lines )
+{
+  std::string buffer;
+  if( Read( input, buffer ) )
+  {
+    lines.clear( );
+    std::istringstream str( buffer );
+    std::string line;
+    while( std::getline( str, line ) )
+      lines.push_back( line );
+    return( true );
+  }
+  else
+    return( false );
+}
+
+// -------------------------------------------------------------------------
+void Includes( TStrings& new_lines, const TStrings& lines )
+{
+  bool ok = true;
+  new_lines.clear( );
+  for( const std::string& line: lines )
+  {
+    std::size_t a = line.find_first_of( "$" );
+    std::size_t b = line.find( "$include", a );
+    if( a == b && a != std::string::npos )
+    {
+      std::size_t s = line.find_first_of( "\"" );
+      std::size_t l = line.find_last_of( "\"" );
+      std::string fname = line.substr( s + 1, l - s - 1 );
+      std::set< TPath >::const_iterator pIt = Data.IncludePaths.begin( );
+      bool found = false;
+      while( pIt != Data.IncludePaths.end( ) && !found )
+      {
+        TPath incl = *pIt;
+        incl /= fname;
+        if( boost::filesystem::exists( incl ) )
+        {
+          TStrings incl_lines;
+          if( Lines( incl.string( ), incl_lines ) )
+          {
+            for( const std::string& l: incl_lines )
+            {
+              if( l.find( "$include" ) != std::string::npos )
+                ok = false;
+              new_lines.push_back( l );
+
+            } // rof
+
+          } // fi
+          found = true;
+
+        } // fi
+        pIt++;
+
+      } // elihw
+    }
+    else
+      new_lines.push_back( line );
+
+  } // rof
+
+  if( !ok )
+  {
+    TStrings new_new_lines;
+    Includes( new_new_lines, new_lines );
+    new_lines = new_new_lines;
+
+  } // fi
+}
+
+// -------------------------------------------------------------------------
+void Definitions( TDefinitions& defs, const TStrings& lines )
+{
+  // Tokenizer
+  typedef boost::char_separator< char > _TSep;
+  typedef boost::tokenizer< _TSep > _TTok;
+
+  // Identify definitions
+  for( const std::string& line: lines )
+  {
+    std::size_t a = line.find_first_not_of( " \t" );
+    if( a != std::string::npos )
+    {
+      if( line[ a ] == '$' )
+      {
+        _TTok tokens( line, _TSep( "=;" ) );
+        _TTok::const_iterator t = tokens.begin( );
+        std::string d = *t + "$";
+
+        std::pair< TDefinitions::iterator, bool > i =
+          defs.insert( TDefinitions::value_type( d, TStrings( ) ) );
+        if( i.second )
+        {
+          for( ++t; t != tokens.end( ); ++t )
+            i.first->second.push_back( *t );
+          if( i.first->second.size( ) == 0 )
+            defs.erase( i.first );
+        }
+        else
+          throw std::runtime_error( "Duplicated defition: " + d );
+
+      } // fi
+
+    } // fi
+
+  } // rof
+
+  // Expand definitions
+  bool stop = false;
+  while( !stop )
+  {
+    // Change all possible values
+    for( TDefinitions::value_type& d: defs )
+    {
+      TStrings nValues;
+      for( const std::string& v: d.second )
+      {
+        std::size_t a = v.find_first_of( "$" );
+        if( a != std::string::npos )
+        {
+          std::size_t b = v.find_first_of( "$", a + 1 );
+          std::string c = v.substr( a, b - a + 1 );
+          TDefinitions::const_iterator cIt = defs.find( c );
+          if( cIt != defs.end( ) )
+          {
+            for( std::string cV: cIt->second )
+            {
+              std::string vnew = v;
+              boost::algorithm::replace_all( vnew, c, cV );
+              nValues.push_back( vnew );
+
+            } // rof
+
+          } // fi
+        }
+        else
+          nValues.push_back( v );
+
+      } // rof
+      d.second = nValues;
+
+    } // rof
+
+    // Check stop
+    stop = true;
+    for( TDefinitions::value_type& d: defs )
+    {
+      for( const std::string& v: d.second )
+        stop &= ( v.find_first_of( "$" ) == std::string::npos );
+
+    } // rof
+
+  } // elihw
+
+  // Clear definitions
+  TDefinitions::iterator dIt = defs.begin( );
+  while( dIt != defs.end( ) )
+  {
+    if( dIt->second.size( ) == 0 )
+    {
+      TDefinitions::iterator eIt = dIt;
+      dIt++;
+      defs.erase( eIt );
+    }
+    else
+      dIt++;
+
+  } // elihw
+}
+
+// -------------------------------------------------------------------------
+int Parse( )
+{
+  // Parse lines
+  std::stringstream lines;
+  for( const std::string& line: Data.InputLines )
+  {
+    // Check if a this is a definition line
+    std::size_t a = line.find_first_of( "$" );
+    std::size_t b = line.find_first_of( "=" );
+    bool ok = true;
+    if( a != std::string::npos && b != std::string::npos )
+    {
+      std::string c = line.substr( a, b - a ) + "$";
+      if( Data.Definitions.find( c ) != Data.Definitions.end( ) )
+        ok = false;
+
+    } // fi
+
+    if( a != std::string::npos )
+    {
+      if( a == line.find( "$include", a ) )
+        ok = false;
+
+    } // fi
+
+    if( ok )
+    {
+      std::string t = line;
+
+      std::set< std::string > tags;
+      for( const TDefinitions::value_type& d: Data.Definitions )
+      {
+        if( line.find( d.first ) != std::string::npos )
+          tags.insert( d.first );
+
+      } // rof
+
+      if( tags.size( ) > 0 )
+      {
+        std::stringstream pre, pos;
+        std::set< std::string >::const_iterator tIt = tags.begin( );
+        std::set< std::string >::const_reverse_iterator rtIt = tags.rbegin( );
+        for( ; tIt != tags.end( ); ++tIt, ++rtIt )
+        {
+          pre << "{{#" << tIt->substr( 1, tIt->size( ) - 2 ) << "}}";
+          pos << "{{/" << rtIt->substr( 1, rtIt->size( ) - 2 ) << "}}";
+          boost::algorithm::replace_all(
+            t, *tIt, "{{" + tIt->substr( 1, tIt->size( ) - 2 ) + "}}"
+            );
+
+        } // rof
+        pre << std::endl << t << std::endl << pos.str( );
+        t = pre.str( );
+
+      } // fi
+      lines << t << std::endl;
+
+    } // fi
+
+  } // rof
+
+
+  // Create moustache context
+  typedef std::pair< std::string, std::string >  TStringPair;
+  typedef std::pair< std::string, mstch::array > TStringArrayPair;
+  mstch::map context;
+  for( const TDefinitions::value_type& d: Data.Definitions )
+  {
+    mstch::array values;
+    std::string c = d.first.substr( 1, d.first.size( ) - 2 );
+    for( const std::string& v: d.second )
+    {
+      mstch::map def;
+      def.insert( TStringPair( c, v ) );
+      values.push_back( def );
+
+    } // rof
+    context.insert( TStringArrayPair( c, values ) );
+
+  } // rof
+
+  // Parse  moustache syntax and save output file
+  std::ofstream out( Data.Output.string( ).c_str( ) );
+  if( !out )
+  {
+    std::cerr
+      << "===============================" << std::endl
+      << "Error caught: " << std::endl
+      << "could not save to output file \"" << Data.Output.string( )
+      << "\"" << std::endl
+      << "===============================" << std::endl
+      << std::endl;
+    return( 1 );
+
+  } // fi
+
+  Render( out, lines.str( ), context );
+  out << std::endl;
+  out.close( );
+  return( 0 );
+}
+
+// -------------------------------------------------------------------------
+void Render( std::ostream& out, const std::string& in, mstch::map& context )
+{
+  std::string s = mstch::render( in, context );
+  boost::algorithm::replace_all( s, "&lt;", "<" );
+  boost::algorithm::replace_all( s, "&gt;", ">" );
+  out << s;
+}
+
+// eof - $RCSfile$