config.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 #include <fstream>
00031 #include <sstream>
00032 
00033 #include "rviz/config.h"
00034 #include "rviz/uniform_string_stream.h"
00035 
00036 namespace rviz
00037 {
00038 
00039 bool Config::readFromFile( const std::string& filename )
00040 {
00041   std::ifstream in( filename.c_str() );
00042   if( in )
00043   {
00044     read( in );
00045     error_message_ = "";
00046     return true;
00047   }
00048   else
00049   {
00050     error_message_ = "Config file '" + filename + "' could not be opened for reading.";
00051     return false;
00052   }
00053 }
00054 
00055 bool Config::writeToFile( const std::string& filename )
00056 {
00057   std::ofstream out( filename.c_str() );
00058   if( out )
00059   {
00060     write( out );
00061     error_message_ = "";
00062     return true;
00063   }
00064   else
00065   {
00066     error_message_ = "Config file '" + filename + "' could not be opened for writing.";
00067     return false;
00068   }
00069 }
00070 
00071 void Config::read( std::istream& input )
00072 {
00073   size_t equals_sign_index;
00074   std::string line;
00075   std::string current_dir;
00076   std::string key, value;
00077 
00078   // Loop over all lines.
00079   while( !input.eof() && !input.fail() )
00080   {
00081     // Read the next line.
00082     line.clear();
00083     std::getline( input, line );
00084 
00085     if( line.size() > 0 ) // Ignore empty lines.
00086     {
00087       if( line[0] == '[' ) // Keep track of the current "directory" to prepend to the keys.
00088       {
00089         current_dir = line.substr( 1, line.size() - 2 );
00090       }
00091       else
00092       {
00093         // Parse a key=value line.
00094         equals_sign_index = line.find_first_of( '=' );
00095         key = line.substr( 0, equals_sign_index );
00096         key = unescapeKey( key );
00097         value = line.substr( equals_sign_index + 1 );
00098 
00099         // Store the key,value pair if the key is not empty.
00100         if( key.size() > 0 )
00101         {
00102           if( current_dir.size() > 0 )
00103           {
00104             key = current_dir + '/' + key;
00105           }
00106           set( key, value );
00107         }
00108       }
00109     }
00110   }
00111 }
00112 
00113 void Config::write( std::ostream& output )
00114 {
00115   std::string last_prefix;
00116   std::string key_tail;
00117   std::string key_prefix;
00118 
00119   for( Iterator it = begin(); it != end(); it++ )
00120   {
00121     const std::string& key = (*it).first;
00122     const std::string& value = (*it).second;
00123     size_t last_slash_index = key.find_last_of( '/' );
00124     if( last_slash_index == std::string::npos )
00125     {
00126       key_tail = key;
00127       key_prefix = "";
00128     }
00129     else
00130     {
00131       key_tail = key.substr( last_slash_index + 1 );
00132       key_prefix = key.substr( 0, last_slash_index );
00133     }
00134     if( key_prefix != last_prefix )
00135     {
00136       writeDirectory( output, key_prefix, last_prefix );
00137     }
00138     key_tail = escapeKey( key_tail );
00139     output << key_tail << "=" << value << std::endl;
00140     last_prefix = key_prefix;
00141   }
00142 }
00143 
00144 // Write a directory description of new_dir to output, given that
00145 // we were previously "in" prev_dir.  For example:
00146 //
00147 // new_dir = a/c, prev_dir = a/b/z, output:
00148 //   [a/c]
00149 //
00150 // new_dir = a/c, prev_dir = a, output:
00151 //   [a/c]
00152 //
00153 // new_dir = a/c, prev_dir = "", output:
00154 //   [a]
00155 //   [a/c]
00156 //
00157 // new_dir = a/c, prev_dir = "b", output:
00158 //   [a]
00159 //   [a/c]
00160 //
00161 // new_dir = a/b/c, prev_dir = "a", output:
00162 //   [a/b]
00163 //   [a/b/c]
00164 //
00165 // new_dir = a/b/c, prev_dir = "a/z/y", output:
00166 //   [a/b]
00167 //   [a/b/c]
00168 void Config::writeDirectory( std::ostream& output, const std::string& new_dir, const std::string& prev_dir )
00169 {
00170   // Find common initial substring between new_dir and prev_dir
00171   size_t min_size = new_dir.size() < prev_dir.size() ? new_dir.size() : prev_dir.size();
00172 
00173   size_t index = 0; // index of first non-matching char.
00174   for( ; index < min_size; index++ )
00175   {
00176     if( new_dir[ index ] != prev_dir[ index ] )
00177     {
00178       break;
00179     }
00180   }
00181 
00182   // If we are pointed at a '/' move just past it.
00183   if( index < new_dir.size() && new_dir[ index ] == '/' )
00184   {
00185     index++;
00186   }
00187 
00188   // Search forward for first '/' after the matching part.  That will
00189   // be the end of the first string we need to print.
00190   bool done = false;
00191   while( !done )
00192   {
00193     index = new_dir.find_first_of( '/', index );
00194     if( index == std::string::npos )
00195     {
00196       index = new_dir.size();
00197       done = true;
00198     }
00199     output << '[' << new_dir.substr( 0, index ) << ']' << std::endl;
00200     index++; // Skip the '/'
00201   }
00202 }
00203 
00204 std::string Config::escapeKey( const std::string& raw_key )
00205 {
00206   std::istringstream in( raw_key );
00207   std::ostringstream out;
00208   char c;
00209   while( in.good() )
00210   {
00211     c = in.get();
00212     if( in )
00213     {
00214       switch( c )
00215       {
00216       case ':':
00217       case ' ':
00218       case '\\':
00219         out << '\\';
00220       }
00221       out << c;
00222     }
00223   }
00224   return out.str();
00225 }
00226 
00227 std::string Config::unescapeKey( const std::string& cooked_key )
00228 {
00229   std::istringstream in( cooked_key );
00230   std::ostringstream out;
00231   char c;
00232   while( in.good() )
00233   {
00234     c = in.get();
00235     if( in.good() )
00236     {
00237       if( c == '\\' )
00238       {
00239         c = in.get();
00240         if( in.good() )
00241         {
00242           out << c;
00243         }
00244       }
00245       else
00246       {
00247         out << c;
00248       }
00249     }
00250   }
00251   return out.str();
00252 }
00253 
00254 void Config::set( const std::string& key, const std::string& value )
00255 {
00256   map_[ stripFirstSlash( key )] = value;
00257 }
00258 
00259 void Config::set( const std::string& key, float value )
00260 {
00261   UniformStringStream ss;
00262   ss << value;
00263   map_[ stripFirstSlash( key )] = ss.str();
00264 }
00265 
00266 void Config::set( const std::string& key, int value )
00267 {
00268   UniformStringStream ss;
00269   ss << value;
00270   map_[ stripFirstSlash( key )] = ss.str();
00271 }
00272 
00273 bool Config::get( const std::string& key, std::string* output, const std::string& default_value )
00274 {
00275   Iterator it = map_.find( stripFirstSlash( key ));
00276   if( it != map_.end() )
00277   {
00278     *output = (*it).second;
00279     return true;
00280   }
00281   *output = default_value;
00282   return false;
00283 }
00284 
00285 bool Config::get( const std::string& key, float* output, float default_value )
00286 {
00287   Iterator it = map_.find( stripFirstSlash( key ));
00288   if( it != map_.end() )
00289   {
00290     UniformStringStream ss;
00291     ss.str( (*it).second );
00292     ss.parseFloat( *output );
00293     if( !ss.fail() )
00294     {
00295       return true;
00296     }
00297   }
00298   *output = default_value;
00299   return false;
00300 }
00301 
00302 bool Config::get( const std::string& key, int* output, int default_value )
00303 {
00304   Iterator it = map_.find( stripFirstSlash( key ));
00305   if( it != map_.end() )
00306   {
00307     UniformStringStream ss;
00308     ss.str( (*it).second );
00309     ss >> *output;
00310     if( !ss.fail() )
00311     {
00312       return true;
00313     }
00314   }
00315   *output = default_value;
00316   return false;
00317 }
00318 
00319 const std::string Config::stripFirstSlash( const std::string& str )
00320 {
00321   if( str[0] == '/' )
00322   {
00323     return str.substr( 1 );
00324   }
00325   else
00326   {
00327     return str;
00328   }
00329 }
00330 
00331 bool Config::DirectoryCompare::operator() (const std::string& lhs, const std::string& rhs) const
00332 {
00333   int start = 0;
00334   int count;
00335   int rhs_count;
00336   size_t l_slash_index, r_slash_index;
00337   bool l_on_last, r_on_last;
00338 
00339   // Loop once for each section of the strings (where sections are
00340   // delimited by '/' characters) as long as the corresponding
00341   // sections are equal.  When we come to a section in which lhs !=
00342   // rhs, return either true or false.
00343   while( true )
00344   {
00345     // Find the index of the next slash in each string, if there is one.
00346     l_slash_index = lhs.find_first_of( '/', start );
00347     r_slash_index = rhs.find_first_of( '/', start );
00348     l_on_last = ( l_slash_index == std::string::npos );
00349     if( l_on_last )
00350     {
00351       l_slash_index = lhs.size();
00352     }
00353     r_on_last = ( r_slash_index == std::string::npos );
00354     if( r_on_last )
00355     {
00356       r_slash_index = rhs.size();
00357     }
00358 
00359     // If one but not both of the strings is on the last section, we
00360     // know the result.  A string which is on its last element is
00361     // "less" than a string which has more elements coming, regardless
00362     // of the current-element comparison.
00363     if( !l_on_last && r_on_last )
00364     {
00365       return false;
00366     }
00367     if( l_on_last && !r_on_last )
00368     {
00369       return true;
00370     }
00371 
00372     // Update the comparison lengths.
00373     count = l_slash_index - start;
00374     rhs_count = r_slash_index - start;
00375 
00376     // Compare the current section of each string.
00377     int result = lhs.compare( start, count, rhs, start, rhs_count );
00378 
00379     // If the sections differ, return true or false according to the
00380     // direction of difference.
00381     if( result != 0 )
00382     {
00383       return result < 0;
00384     }
00385 
00386     // The sections are equal, so if the rhs is ending, then the rhs
00387     // is less, so return false.
00388     if( start + rhs_count >= (int)rhs.size() )
00389     {
00390       return false;
00391     }
00392 
00393     // Move start index to the next section, skipping over the '/'
00394     // character with the +1.
00395     start += count + 1;
00396 
00397     // The sections are equal, so if the lhs is ending, it is less, so
00398     // return true.
00399     if( start > (int)lhs.size() )
00400     {
00401       return true;
00402     }
00403   }
00404 }
00405 
00406 } // end namespace rviz


rviz
Author(s): Dave Hershberger, Josh Faust
autogenerated on Mon Jan 6 2014 11:54:32