// @(#)root/core:$Id$ // author: Lukasz Janyst #include "RConversionRuleParser.h" #include "TSchemaRuleProcessor.h" #include "TMetaUtils.h" #include #include #include #include #include #include namespace { static void RemoveEscapeSequences(std::string& rawString) { const std::vector> subPairs { {"\\\\","\\"}, {"\\\"","\""}, {"\\\'","\'"}}; size_t start_pos = 0; for (auto const & subPair : subPairs){ start_pos = 0; auto from = subPair.first; auto to = subPair.second; while((start_pos = rawString.find(from, start_pos)) != std::string::npos) { rawString.replace(start_pos, from.length(), to); start_pos += to.length(); } } } } namespace ROOT { using namespace Internal; typedef std::list > SourceTypeList_t; //-------------------------------------------------------------------------- // Allocate global variables ///////////////////////////////////////////////////////////////////////////// SchemaRuleClassMap_t gReadRules; SchemaRuleClassMap_t gReadRawRules; static Bool_t ValidateRule( const std::map& rule, std::string &error_string ); static std::string::size_type FindEndSymbol(std::string &command) { // Find the end of a symbol. if (command.length() == 0) return std::string::npos; std::string::size_type cursor; unsigned int level = 0; for (cursor = 0 ; cursor < command.length(); ++cursor) { switch( command[cursor] ) { case ' ': case '\t': case '\r': case '=': if (level==0) { std::string::size_type sub_cursor = cursor; while( isspace(command[sub_cursor]) ) { ++sub_cursor; } if ( command[sub_cursor] == '=' ) { return sub_cursor; } else { return cursor; } } else { break; } case '<': ++level; break; case '>': if (level==0) { return std::string::npos; } --level; break; default: { // nothing to do } }; } return cursor; } ///////////////////////////////////////////////////////////////////////////// /// Parse the schema rule as specified in the LinkDef file Bool_t ParseRule( std::string command, std::map &result, std::string &error_string ) { std::string::size_type l=0; command = TSchemaRuleProcessor::Trim( command ); //----------------------------------------------------------------------- // Remove the semicolon from the end if declared ////////////////////////////////////////////////////////////////////////// if( command[command.size()-1] == ';' ) command = command.substr( 0, command.size()-1 ); //----------------------------------------------------------------------- // If the first symbol does not end is not followed by equal then it // defaults to being the sourceClass. ////////////////////////////////////////////////////////////////////////// { std::string::size_type endsymbol = FindEndSymbol( command ); if ( endsymbol == command.length() || command[endsymbol] == ' ' || command[endsymbol] == '\t' ) { // std::string::size_type space_pos = command.find( ' ' ); // std::string::size_type equal_pos = command.find( '=' ); // if ( space_pos < equal_pos) { std::string value = TSchemaRuleProcessor::Trim( command.substr( 0, endsymbol ) ); result["sourceClass"] = value; result["targetClass"] = value; if (endsymbol < command.length()) { command = TSchemaRuleProcessor::Trim( command.substr( endsymbol+1 ) ); } else { command.clear(); } //----------------------------------------------------------------------- // If the first symbol is the targetClass then the 2nd symbol can be // the source data member name. //----------------------------------------------------------------------- // space_pos = command.find( ' ' ); // equal_pos = command.find( '=' ); // if ( space_pos < equal_pos ) { endsymbol = FindEndSymbol( command ); if ( endsymbol == command.length() || command[endsymbol] == ' ' || command[endsymbol] == '\t' ) { std::string membervalue = TSchemaRuleProcessor::Trim( command.substr( 0, endsymbol ) ); result["source"] = membervalue; result["target"] = membervalue; command = TSchemaRuleProcessor::Trim( command.substr( endsymbol+1 ) ); } } } //----------------------------------------------------------------------- // Process the input until there are no characters left ////////////////////////////////////////////////////////////////////////// while( !command.empty() ) { //-------------------------------------------------------------------- // Find key token /////////////////////////////////////////////////////////////////////// std::string::size_type pos = command.find( '=' ); //-------------------------------------------------------------------- // No equality sign found - no keys left /////////////////////////////////////////////////////////////////////// if( pos == std::string::npos ) { error_string = "Parsing error, no key found!"; return false; } //-------------------------------------------------------------------- // The key was found - process the arguments /////////////////////////////////////////////////////////////////////// std::string key = TSchemaRuleProcessor::Trim( command.substr( 0, pos ) ); command = TSchemaRuleProcessor::Trim( command.substr( pos+1 ) ); //-------------------------------------------------------------------- // Nothing left to be processed /////////////////////////////////////////////////////////////////////// if( command.size() < 1 ) { error_string = "Parsing error, wrond or no value specified for key: " + key; return false; } Bool_t hasquote = command[0] == '"'; //-------------------------------------------------------------------- // Processing code tag: "{ code }" /////////////////////////////////////////////////////////////////////// if( key == "code" ) { if( command[1] != '{' ) { error_string = "Parsing error while processing key: code\n"; error_string += "Expected \"{ at the beginning of the value."; return false; } l = command.find( "}\"" ); if( l == std::string::npos ) { error_string = "Parsing error while processing key: \"" + key + "\"\n"; error_string += "Expected }\" at the end of the value."; return false; } auto rawCode = command.substr( 2, l-2 ); RemoveEscapeSequences(rawCode); result[key] = rawCode; ++l; } //-------------------------------------------------------------------- // Processing normal tag: "value" /////////////////////////////////////////////////////////////////////// else { if( hasquote) { l = command.find( '"', 1 ); if (l == std::string::npos ) { error_string = "\nParsing error while processing key: \"" + key + "\"\n"; error_string += "Expected \" at the end of the value."; return false; } result[key] = command.substr( 1, l-1 ); } else { l = command.find(' ', 1); if (l == std::string::npos) l = command.size(); result[key] = command.substr( 0, l ); } } //-------------------------------------------------------------------- // Everything went ok /////////////////////////////////////////////////////////////////////// if( l == command.size() ) break; command = command.substr( l+1 ); } std::map::const_iterator it1; it1 = result.find("oldtype"); if ( it1 != result.end() ) { std::map::const_iterator it2; it2 = result.find("source"); if ( it2 != result.end() ) { result["source"] = it1->second + " " + it2->second; } } if ( result.find("version") == result.end() && result.find("checksum") == result.end() ) { result["version"] = "[1-]"; } //------------------------------------------------------------------------ // "include" tag. Replace ";" with "," for backwards compatibility with // ROOT5 ////////////////////////////////////////////////////////////////////////// auto const includeKeyName = "include"; auto includeTag = result.find(includeKeyName); if (includeTag != result.end()){ auto & includeTagValue = includeTag->second; std::replace_if (includeTagValue.begin(), includeTagValue.end(), [](char c){ return c == ';';}, ','); result[includeKeyName] = includeTagValue; } return ValidateRule( result, error_string); } ///////////////////////////////////////////////////////////////////////////// /// Validate if the user specified rules are correct static Bool_t ValidateRule( const std::map& rule, std::string &error_string ) { //----------------------------------------------------------------------- // Check if we have target class name ////////////////////////////////////////////////////////////////////////// std::map::const_iterator it1, it2; std::list lst; std::list::iterator lsIt; it1 = rule.find( "targetClass" ); if( it1 == rule.end() ) { error_string = "WARNING: You always have to specify the targetClass "; error_string += "when specyfying an IO rule"; return false; } std::string className = TSchemaRuleProcessor::Trim( it1->second ); std::string warning = "WARNING: IO rule for class " + className; //----------------------------------------------------------------------- // Check if we have the source tag ////////////////////////////////////////////////////////////////////////// it1 = rule.find( "sourceClass" ); if( it1 == rule.end()) { error_string = warning + " - sourceClass parameter is missing"; return false; } //----------------------------------------------------------------------- // Check if we have either version or checksum specified ////////////////////////////////////////////////////////////////////////// it1 = rule.find( "version" ); it2 = rule.find( "checksum" ); if( it1 == rule.end() && it2 == rule.end() ) { error_string = warning + " - you need to specify either version or "; error_string += "checksum"; return false; } //----------------------------------------------------------------------- // Check if the checksum has been set to right value ////////////////////////////////////////////////////////////////////////// if( it2 != rule.end() ) { if( it2->second.size() < 2 || it2->second[0] != '[' || it2->second[it2->second.size()-1] != ']' ) { error_string = warning + " - a comma separated list of ints"; error_string += " enclosed in square brackets expected"; error_string += " as a value of checksum parameter"; return false; } TSchemaRuleProcessor::SplitList( it2->second.substr( 1, it2->second.size()-2 ), lst ); if( lst.empty() ) { std::cout << warning << " - the list of checksums is empty"; std::cout << std::endl; } for( lsIt = lst.begin(); lsIt != lst.end(); ++lsIt ) if( !TSchemaRuleProcessor::IsANumber( *lsIt ) ) { error_string = warning + " - " + *lsIt + " is not a valid value"; error_string += " of checksum parameter - an integer expected"; return false; } } //----------------------------------------------------------------------- // Check if the version is correct ////////////////////////////////////////////////////////////////////////// std::pair ver; if( it1 != rule.end() ) { if( it1->second.size() < 2 || it1->second[0] != '[' || it1->second[it1->second.size()-1] != ']' ) { error_string = warning + " - a comma separated list of version specifiers "; error_string += "enclosed in square brackets expected"; error_string += "as a value of version parameter"; return false; } TSchemaRuleProcessor::SplitList( it1->second.substr( 1, it1->second.size()-2 ), lst ); if( lst.empty() ) { error_string = warning + " - the list of versions is empty"; } for( lsIt = lst.begin(); lsIt != lst.end(); ++lsIt ) if( !TSchemaRuleProcessor::ProcessVersion( *lsIt, ver ) ) { error_string = warning + " - " + *lsIt + " is not a valid value"; error_string += " of version parameter"; return false; } } //----------------------------------------------------------------------- // Check if we're dealing with renameing declaration - sourceClass, // targetClass and either version or checksum required ////////////////////////////////////////////////////////////////////////// if( rule.size() == 3 || (rule.size() == 4 && it1 != rule.end() && it2 != rule.end()) ) return true; //----------------------------------------------------------------------- // Check if we have all the keys we need //----------------------------------------------------------------------- std::string keys[] = {"target", "source"}; for( int i = 0; i < 2; ++i ) { it1 = rule.find( keys[i] ); if( it1 == rule.end() ) { error_string = warning + " - required parameter is missing: "; error_string += keys[i]; return false; } } //----------------------------------------------------------------------- // Check the source contains proper declarations. ////////////////////////////////////////////////////////////////////////// it1 = rule.find("code"); if (it1 != rule.end() && it1->second != "") { SourceTypeList_t source; TSchemaRuleProcessor::SplitDeclaration( rule.find("source")->second, source ); SourceTypeList_t::const_iterator it; for( it = source.begin(); it != source.end(); ++it ) { if ( ( it->first.fType == "" && it->second != "") ) { error_string = warning + " - type required when listing a rule's source: "; error_string += "source=\""+ rule.find("source")->second +"\""; return false; } } } //----------------------------------------------------------------------- // Check if we have an embed parameter and if so if it has been set to // the right value ////////////////////////////////////////////////////////////////////////// it1 = rule.find( "embed" ); if( it1 != rule.end() ) { std::string emValue = TSchemaRuleProcessor::Trim( it1->second ); if( emValue != "true" && emValue != "false" ) { error_string = warning + " - true or false expected as a value "; error_string += "of embed parameter"; return false; } } //----------------------------------------------------------------------- // Check if the include list is not empty ////////////////////////////////////////////////////////////////////////// it1 = rule.find( "include" ); if( it1 != rule.end() ) { if( it1->second.empty() ) { error_string = warning + " - the include list is empty"; return false; } } return true; } ///////////////////////////////////////////////////////////////////////////// /// Check if given rule contains references to valid data members Bool_t HasValidDataMembers(SchemaRuleMap_t& rule, MembersTypeMap_t& members ) { std::list mem; std::list::iterator it; // MembersMap_t::iterator rIt; TSchemaRuleProcessor::SplitList( rule["target"], mem ); //----------------------------------------------------------------------- // Loop over the data members ////////////////////////////////////////////////////////////////////////// for( it = mem.begin(); it != mem.end(); ++it ) { if( members.find( *it ) == members.end() ) { std::cout << "WARNING: IO rule for class " + rule["targetClass"]; std::cout << " data member: " << *it << " was specified as a "; std::cout << "target in the rule but doesn't seem to appear in "; std::cout << "target class" << std::endl; return false; } } return true; } ///////////////////////////////////////////////////////////////////////////// ///----------------------------------------------------------------------- /// Write down the sources ///----------------------------------------------------------------------- static void WriteAutoVariables( const std::list& target, const SourceTypeList_t& source, MembersTypeMap_t& members, std::string& className, std::string& mappedName, std::ostream& output ) { if (!source.empty()) { Bool_t start = true; SourceTypeList_t::const_iterator it; //-------------------------------------------------------------------- // Write IDs and check if we should generate the onfile structure // this is done if the type was declared /////////////////////////////////////////////////////////////////////// Bool_t generateOnFile = false; output << "#if 0" << std::endl; // this is to be removed later for( it = source.begin(); it != source.end(); ++it ) { output << " "; output << "static Int_t id_" << it->second << " = oldObj->GetId("; output << "\"" << it->second << "\");" << std::endl; if( it->first.fType != "" ) generateOnFile = true; } output << "#endif" << std::endl; // this is to be removed later //-------------------------------------------------------------------- // Declare the on-file structure - if needed /////////////////////////////////////////////////////////////////////// if( generateOnFile ) { std::string onfileStructName = mappedName + "_Onfile"; output << " "; output << "struct " << onfileStructName << " {\n"; //----------------------------------------------------------------- // List the data members with non-empty type declarations //////////////////////////////////////////////////////////////////// /// fprintf(stderr, "Seeing %s %s %s\n", it->first.fType.c_str(), it->second.c_str(), it->first.fDimensions.c_str()); for( it = source.begin(); it != source.end(); ++it ) { if( it->first.fType.size() ) { if ( it->first.fDimensions.size() ) { output << " typedef " << it->first.fType; output << " onfile_" << it->second << "_t" << it->first.fDimensions << ";\n"; output << " "; output << "onfile_" << it->second << "_t &" << it->second << ";\n"; } else { output << " "; output << it->first.fType << " &" << it->second << ";\n"; } } } //----------------------------------------------------------------- // Generate the constructor //////////////////////////////////////////////////////////////////// output << " " << onfileStructName << "("; for( start = true, it = source.begin(); it != source.end(); ++it ) { if( it->first.fType.size() == 0) continue; if( !start ) output << ", "; else start = false; if (it->first.fDimensions.size() == 0) { output << it->first.fType << " &onfile_" << it->second; } else { output << " onfile_" << it->second << "_t" << " &onfile_" << it->second; } } output << " ): "; //----------------------------------------------------------------- // Generate the constructor's initializer list //////////////////////////////////////////////////////////////////// for( start = true, it = source.begin(); it != source.end(); ++it ) { if( it->first.fType == "" ) continue; if( !start ) output << ", "; else start = false; output << it->second << "(onfile_" << it->second << ")"; } output << " {}\n"; output << " " << "};\n"; //----------------------------------------------------------------- // Initialize the structure - to be changed later //////////////////////////////////////////////////////////////////// for( it = source.begin(); it != source.end(); ++it ) { output << " "; output << "static Long_t offset_Onfile_" << mappedName; output << "_" << it->second << " = oldObj->GetClass()->GetDataMemberOffset(\""; output << it->second << "\");\n"; } output << " " << "char *onfile_add = (char*)oldObj->GetObject();\n"; output << " " << mappedName << "_Onfile onfile(\n"; for( start = true, it = source.begin(); it != source.end(); ++it ) { if( it->first.fType == "" ) continue; if( !start ) output << ",\n"; else start = false; output << " "; output << "*("; if (it->first.fDimensions.size() == 0) { output << it->first.fType; } else { output << mappedName << "_Onfile::onfile_" << it->second << "_t"; } output << "*)(onfile_add+offset_Onfile_"; output << mappedName << "_" << it->second << ")"; } output << " );\n\n"; } } //----------------------------------------------------------------------- // Write down the targets ////////////////////////////////////////////////////////////////////////// if( !target.empty() ) { output << " static TClassRef cls(\""; output << className << "\");" << std::endl; std::list::const_iterator it; for( it = target.begin(); it != target.end(); ++it ) { Internal::TSchemaType memData = members[*it]; output << " static Long_t offset_" << *it << " = "; output << "cls->GetDataMemberOffset(\"" << *it << "\");"; output << std::endl; if (memData.fDimensions.size()) { output << " typedef " << memData.fType << " " << *it << "_t" << memData.fDimensions << ";" << std::endl; output << " " << *it << "_t& " << *it << " = "; output << "*(" << *it << "_t *)(target+offset_" << *it; output << ");" << std::endl; } else { output << " " << memData.fType << "& " << *it << " = "; output << "*(" << memData.fType << "*)(target+offset_" << *it; output << ");" << std::endl; } } } } ///////////////////////////////////////////////////////////////////////////// /// Write the conversion function for Read rule, the function name /// is being written to rule["funcname"] void WriteReadRuleFunc( SchemaRuleMap_t& rule, int index, std::string& mappedName, MembersTypeMap_t& members, std::ostream& output ) { std::string className = rule["targetClass"]; //----------------------------------------------------------------------- // Create the function name ////////////////////////////////////////////////////////////////////////// std::ostringstream func; func << "read_" << mappedName << "_" << index; rule["funcname"] = func.str(); //----------------------------------------------------------------------- // Write the header ////////////////////////////////////////////////////////////////////////// output << " static void " << func.str(); output << "( char* target, TVirtualObject *oldObj )" << std::endl; output << " {" << std::endl; output << " //--- Automatically generated variables ---" << std::endl; //----------------------------------------------------------------------- // Write the automatically generated variables ////////////////////////////////////////////////////////////////////////// std::list > source; std::list target; TSchemaRuleProcessor::SplitDeclaration( rule["source"], source ); TSchemaRuleProcessor::SplitList( rule["target"], target ); WriteAutoVariables( target, source, members, className, mappedName, output ); output << " " << className << "* newObj = (" << className; output << "*)target;" << std::endl; output << " // Supress warning message.\n"; output << " " << "if (oldObj) {}\n\n"; output << " " << "if (newObj) {}\n\n"; //----------------------------------------------------------------------- // Write the user's code ////////////////////////////////////////////////////////////////////////// output << " //--- User's code ---" << std::endl; output << " " << rule["code"] << std::endl; output << " }" << std::endl; } ///////////////////////////////////////////////////////////////////////////// /// Write the conversion function for ReadRaw rule, the function name /// is being written to rule["funcname"] void WriteReadRawRuleFunc( SchemaRuleMap_t& rule, int index, std::string& mappedName, MembersTypeMap_t& members, std::ostream& output ) { std::string className = rule["targetClass"]; //----------------------------------------------------------------------- // Create the function name ////////////////////////////////////////////////////////////////////////// std::ostringstream func; func << "readraw_" << mappedName << "_" << index; rule["funcname"] = func.str(); //----------------------------------------------------------------------- // Write the header ////////////////////////////////////////////////////////////////////////// output << " static void " << func.str(); output << "( char* target, TBuffer &b )" << std::endl; output << " {" << std::endl; output << "#if 0" << std::endl; output << " //--- Automatically generated variables ---" << std::endl; //----------------------------------------------------------------------- // Write the automatically generated variables ////////////////////////////////////////////////////////////////////////// std::list > source; std::list target; TSchemaRuleProcessor::SplitList( rule["target"], target ); WriteAutoVariables( target, source, members, className, mappedName, output ); output << " " << className << "* newObj = (" << className; output << "*)target;" << std::endl << std::endl; //----------------------------------------------------------------------- // Write the user's code ////////////////////////////////////////////////////////////////////////// output << " //--- User's code ---" << std::endl; output << rule["code"] << std::endl; output << "#endif" << std::endl; output << " }" << std::endl; } ///////////////////////////////////////////////////////////////////////////// /// Replace all accurances of given string with other string static void StrReplace( std::string& proc, const std::string& pat, const std::string& tr ) { std::string::size_type it = 0; std::string::size_type s = pat.size(); std::string::size_type tr_len= tr.size(); if( s == 0 ) return; while( 1 ) { it = proc.find( pat, it ); if( it == std::string::npos ) break; proc.replace( it, s, tr ); it += tr_len; } } ///////////////////////////////////////////////////////////////////////////// /// Write schema rules void WriteSchemaList( std::list& rules, const std::string& listName, std::ostream& output ) { std::list::iterator it; int i = 0; //----------------------------------------------------------------------- // Loop over the rules ////////////////////////////////////////////////////////////////////////// for( it = rules.begin(); it != rules.end(); ++it ) { output << " rule = &" << listName << "[" << i++; output << "];" << std::endl; //-------------------------------------------------------------------- // Write down the mandatory fields /////////////////////////////////////////////////////////////////////// output << " rule->fSourceClass = \"" << (*it)["sourceClass"]; output << "\";" << std::endl; if( it->find( "target" ) != it->end() ) { output << " rule->fTarget = \"" << (*it)["target"]; output << "\";" << std::endl; } if( it->find( "source" ) != it->end() ) { output << " rule->fSource = \"" << (*it)["source"]; output << "\";" << std::endl; } //-------------------------------------------------------------------- // Deal with non mandatory keys /////////////////////////////////////////////////////////////////////// if( it->find( "funcname" ) != it->end() ) { std::string code = (*it)["code"]; StrReplace( code, "\n", "\\n" ); StrReplace( code, "\"", "\\\""); output << " rule->fFunctionPtr = (void *)TFunc2void( "; output << (*it)["funcname"] << ");" << std::endl; output << " rule->fCode = \"" << code; output << "\";" << std::endl; } if( it->find( "version" ) != it->end() ) { output << " rule->fVersion = \"" << (*it)["version"]; output << "\";" << std::endl; } if( it->find( "checksum" ) != it->end() ) { output << " rule->fChecksum = \"" << (*it)["checksum"]; output << "\";" << std::endl; } if( it->find( "embed" ) != it->end() ) { output << " rule->fEmbed = " << (*it)["embed"]; output << ";" << std::endl; } if( it->find( "include" ) != it->end() ) { output << " rule->fInclude = \"" << (*it)["include"]; output << "\";" << std::endl; } if( it->find( "attributes" ) != it->end() ) { output << " rule->fAttributes = \"" << (*it)["attributes"]; output << "\";" << std::endl; } } } ///////////////////////////////////////////////////////////////////////////// /// Get the list of includes specified in the shema rules void GetRuleIncludes( std::list &result ) { std::list tmp; std::list::iterator rule; SchemaRuleMap_t::iterator attr; SchemaRuleClassMap_t::iterator it; //----------------------------------------------------------------------- // Processing read rules ////////////////////////////////////////////////////////////////////////// for( it = gReadRules.begin(); it != gReadRules.end(); ++it ) { for( rule = it->second.begin(); rule != it->second.end(); ++rule ) { attr = rule->find( "include" ); if( attr == rule->end() ) continue; TSchemaRuleProcessor::SplitList( attr->second, tmp ); result.splice( result.begin(), tmp, tmp.begin(), tmp.end() ); } } //----------------------------------------------------------------------- // Processing read raw rules ////////////////////////////////////////////////////////////////////////// for( it = gReadRawRules.begin(); it != gReadRawRules.end(); ++it ) { for( rule = it->second.begin(); rule != it->second.end(); ++rule ) { attr = rule->find( "include" ); if( attr == rule->end() ) continue; TSchemaRuleProcessor::SplitList( attr->second, tmp ); result.splice( result.begin(), tmp, tmp.begin(), tmp.end() ); } } //----------------------------------------------------------------------- // Removing duplicates ////////////////////////////////////////////////////////////////////////// result.sort(); result.unique(); } ///////////////////////////////////////////////////////////////////////////// /// I am being called when a read pragma is encountered void ProcessReadPragma( const char* args ) { //----------------------------------------------------------------------- // Parse the rule and check it's validity ////////////////////////////////////////////////////////////////////////// std::map rule; std::string error_string; if( !ParseRule( args, rule, error_string ) ) { std::cout << error_string << '\n'; std::cout << "The following rule has been omitted:" << std::endl; std::cout << " read " << args << std::endl; return; } //----------------------------------------------------------------------- // Append the rule to the list ////////////////////////////////////////////////////////////////////////// SchemaRuleClassMap_t::iterator it; std::string targetClass = rule["targetClass"]; it = gReadRules.find( targetClass ); if( it == gReadRules.end() ) { std::list lst; lst.push_back( rule ); gReadRules[targetClass] = lst; } else it->second.push_back( rule ); } ///////////////////////////////////////////////////////////////////////////// /// I am being called then a readraw pragma is encountered void ProcessReadRawPragma( const char* args ) { //----------------------------------------------------------------------- // Parse the rule and check it's validity ////////////////////////////////////////////////////////////////////////// std::map rule; std::string error_string; if( !ParseRule( args, rule, error_string ) ) { std::cout << error_string << '\n'; std::cout << "The following rule has been omitted:" << std::endl; std::cout << " readraw " << args << std::endl; return; } //----------------------------------------------------------------------- // Append the rule to the list ////////////////////////////////////////////////////////////////////////// SchemaRuleClassMap_t::iterator it; std::string targetClass = rule["targetClass"]; it = gReadRawRules.find( targetClass ); if( it == gReadRawRules.end() ) { std::list lst; lst.push_back( rule ); gReadRawRules[targetClass] = lst; } else it->second.push_back( rule ); } }