X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=appli%2Fbash%2FMOC.cxx;fp=appli%2Fbash%2FMOC.cxx;h=8052b05210b44fab467978764dcc5da874b16f59;hb=2e142df11d6f312a2a2b5097b8da73571ed523e8;hp=0000000000000000000000000000000000000000;hpb=61b3659afe961ed248f30e26f9ca8f28fcfafddc;p=cpPlugins.git diff --git a/appli/bash/MOC.cxx b/appli/bash/MOC.cxx new file mode 100644 index 0000000..8052b05 --- /dev/null +++ b/appli/bash/MOC.cxx @@ -0,0 +1,438 @@ +// ========================================================================= +// @author Leonardo Florez-Valencia (florez-l@javeriana.edu.co) +// ========================================================================= + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// ------------------------------------------------------------------------- +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, "<", "<" ); + boost::algorithm::replace_all( s, ">", ">" ); + out << s; +} + +// eof - $RCSfile$