OpenWalnut
1.4.0
|
00001 //--------------------------------------------------------------------------- 00002 // 00003 // Project: OpenWalnut ( http://www.openwalnut.org ) 00004 // 00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS 00006 // For more information see http://www.openwalnut.org/copying 00007 // 00008 // This file is part of OpenWalnut. 00009 // 00010 // OpenWalnut is free software: you can redistribute it and/or modify 00011 // it under the terms of the GNU Lesser General Public License as published by 00012 // the Free Software Foundation, either version 3 of the License, or 00013 // (at your option) any later version. 00014 // 00015 // OpenWalnut is distributed in the hope that it will be useful, 00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 // GNU Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public License 00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>. 00022 // 00023 //--------------------------------------------------------------------------- 00024 00025 #include <algorithm> 00026 #include <sstream> 00027 #include <string> 00028 #include <vector> 00029 00030 #include "exceptions/WParseError.h" 00031 #include "exceptions/WNotFound.h" 00032 #include "WIOTools.h" 00033 #include "WPredicateHelper.h" 00034 00035 #include "WStructuredTextParser.h" 00036 00037 namespace WStructuredTextParser 00038 { 00039 const std::string StructuredValueTree::Separator = "/"; 00040 00041 StructuredValueTree::StructuredValueTree( const FileType& file ): 00042 m_file( file ) 00043 { 00044 // initialize member 00045 } 00046 00047 StructuredValueTree::StructuredValueTree() 00048 { 00049 // do nothing. 00050 } 00051 00052 StructuredValueTree::StructuredValueTree( const std::string& toParse ): 00053 m_file( parseFromString( toParse ) ) 00054 { 00055 // initialize 00056 } 00057 00058 StructuredValueTree::StructuredValueTree( const boost::filesystem::path& file ): 00059 m_file( parseFromFile( file ) ) 00060 { 00061 } 00062 00063 StructuredValueTree::~StructuredValueTree() 00064 { 00065 // cleanup 00066 } 00067 00068 bool StructuredValueTree::exists( std::string key, bool valuesOnly ) const 00069 { 00070 return count( key, valuesOnly ); 00071 } 00072 00073 size_t StructuredValueTree::count( std::string key, bool valuesOnly ) const 00074 { 00075 std::vector< ObjectType > rObj; 00076 std::vector< KeyValueType > rKV; 00077 00078 // traverse 00079 traverse( m_file, key, rObj, rKV ); 00080 00081 if( valuesOnly ) 00082 { 00083 return rKV.size(); 00084 } 00085 else 00086 { 00087 return rKV.size() + rObj.size(); 00088 } 00089 } 00090 00091 StructuredValueTree StructuredValueTree::getSubTree( std::string key ) const 00092 { 00093 std::vector< StructuredValueTree > r = getSubTrees( key ); 00094 00095 // return first match if any 00096 if( r.size() ) 00097 { 00098 return *r.begin(); 00099 } 00100 else 00101 { 00102 return StructuredValueTree(); 00103 } 00104 } 00105 00106 std::vector< StructuredValueTree > StructuredValueTree::getSubTrees( std::string key ) const 00107 { 00108 std::vector< ObjectType > rObj; 00109 std::vector< KeyValueType > rKV; 00110 std::vector< StructuredValueTree > r; 00111 00112 // traverse 00113 traverse( m_file, key, rObj, rKV ); 00114 00115 // now we transform each found object int a MemberType (boost variant). 00116 for( std::vector< ObjectType >::const_iterator objects = rObj.begin(); objects != rObj.end(); ++objects ) 00117 { 00118 // create a new StructuredValueTree instance 00119 r.push_back( StructuredValueTree( ( *objects ).m_nodes ) ); 00120 } 00121 00122 return r; 00123 } 00124 00125 void StructuredValueTree::traverse( FileType current, std::string key, 00126 std::vector< ObjectType >& resultObjects, 00127 std::vector< KeyValueType >& resultValues ) const 00128 { 00129 // split up the key 00130 std::vector< std::string > keySplit = string_utils::tokenize( key, Separator, false ); 00131 // empty key -> return empty result list 00132 if( !keySplit.size() ) 00133 { 00134 return; 00135 } 00136 00137 // traverse 00138 for( FileType::const_iterator i = current.begin(); i != current.end(); ++i ) 00139 { 00140 traverse( *i, keySplit.begin(), keySplit.end(), resultObjects, resultValues ); 00141 } 00142 } 00143 00144 void StructuredValueTree::traverse( MemberType current, std::vector< std::string >::const_iterator keyIter, 00145 std::vector< std::string >::const_iterator keyEnd, 00146 std::vector< ObjectType >& resultObjects, 00147 std::vector< KeyValueType >& resultValues ) const 00148 { 00149 // get some properties of the current entry: 00150 std::string elementName = boost::apply_visitor( NameQueryVisitor(), current ); 00151 bool elementIsKeyValuePair = boost::apply_visitor( IsLeafVisitor(), current ); 00152 bool elementIsComment = boost::apply_visitor( IsCommentVisitor(), current ); 00153 00154 // comments will be ignored. 00155 // NOTE: we store comments in the original data structure to allow them to be written again to the file. This can be useful if OW loads a 00156 // file (edited by the user) and re-writes this file. -> we are able to keep the comments 00157 if( elementIsComment ) 00158 { 00159 return; 00160 } 00161 00162 // does the current node match the current name? 00163 if( elementName == *keyIter ) 00164 { 00165 // only if the key path continues AND the current element is no leaf, traverse 00166 if( !elementIsKeyValuePair && ( ( keyIter + 1 ) != keyEnd) ) 00167 { 00168 ObjectType elementAsObj = boost::get< ObjectType >( current ); 00169 for( std::vector< MemberType >::const_iterator nodeIter = elementAsObj.m_nodes.begin(); 00170 nodeIter != elementAsObj.m_nodes.end(); 00171 ++nodeIter ) 00172 { 00173 traverse( *nodeIter, keyIter + 1, keyEnd, resultObjects, resultValues ); 00174 } 00175 } 00176 else if( ( keyIter + 1 ) == keyEnd ) 00177 { 00178 // we now have reached the end of the path. 00179 if( elementIsKeyValuePair ) 00180 { 00181 // the current element is a key-value pair -> add to result vector 00182 resultValues.push_back( boost::get< KeyValueType >( current ) ); 00183 } 00184 else 00185 { 00186 // the element is a object -> add to result vector 00187 resultObjects.push_back( boost::get< ObjectType >( current ) ); 00188 } 00189 } 00190 // all the remaining cases are invalid and cause traversion to stop 00191 } 00192 // done 00193 } 00194 00195 FileType parseFromString( std::string input ) 00196 { 00197 std::ostringstream error; 00198 WStructuredTextParser::Grammar< std::string::const_iterator > parser( error ); 00199 00200 // parse 00201 FileType ast; 00202 std::string::const_iterator iter = input.begin(); 00203 std::string::const_iterator end = input.end(); 00204 bool r = phrase_parse( iter, end, parser, boost::spirit::ascii::space, ast ); 00205 00206 // error? 00207 if( !( r && iter == end ) ) 00208 { 00209 throw WParseError( "Parse error. Parser message: " + error.str() ); 00210 } 00211 00212 // done. return 00213 return ast; 00214 } 00215 00216 FileType parseFromFile( boost::filesystem::path path ) 00217 { 00218 // NOTE: do not catch the io exception here. 00219 std::string input= readFileIntoString( path ); 00220 00221 // instantiate parser 00222 std::ostringstream error; 00223 WStructuredTextParser::Grammar< std::string::const_iterator > parser( error ); 00224 00225 // parse 00226 FileType ast; 00227 std::string::const_iterator iter = input.begin(); 00228 std::string::const_iterator end = input.end(); 00229 bool r = phrase_parse( iter, end, parser, boost::spirit::ascii::space, ast ); 00230 00231 // error? 00232 if( !( r && iter == end ) ) 00233 { 00234 throw WParseError( "Parse error. Parser message: " + error.str() ); 00235 } 00236 00237 // done. return 00238 return ast; 00239 } 00240 } 00241