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 "rviz/config.h"
00031 
00032 #include <fstream>
00033 #include <sstream>
00034 
00035 namespace rviz
00036 {
00037 
00038 bool Config::readFromFile( const std::string& filename )
00039 {
00040   std::ifstream in( filename.c_str() );
00041   if( in )
00042   {
00043     read( in );
00044     return true;
00045   }
00046   else
00047   {
00048     std::cerr << "Config file '" << filename << "' could not be opened for reading." << std::endl;
00049     return false;
00050   }
00051 }
00052 
00053 bool Config::writeToFile( const std::string& filename )
00054 {
00055   std::ofstream out( filename.c_str() );
00056   if( out )
00057   {
00058     write( out );
00059     return true;
00060   }
00061   else
00062   {
00063     std::cerr << "Config file '" << filename << "' could not be opened for writing." << std::endl;
00064     return false;
00065   }
00066 }
00067 
00068 void Config::read( std::istream& input )
00069 {
00070   size_t equals_sign_index;
00071   std::string line;
00072   std::string current_dir;
00073   std::string key, value;
00074 
00075   // Loop over all lines.
00076   while( !input.eof() && !input.fail() )
00077   {
00078     // Read the next line.
00079     line.clear();
00080     std::getline( input, line );
00081 
00082     if( line.size() > 0 ) // Ignore empty lines.
00083     {
00084       if( line[0] == '[' ) // Keep track of the current "directory" to prepend to the keys.
00085       {
00086         current_dir = line.substr( 1, line.size() - 2 );
00087       }
00088       else
00089       {
00090         // Parse a key=value line.
00091         equals_sign_index = line.find_first_of( '=' );
00092         key = line.substr( 0, equals_sign_index );
00093         key = unescapeKey( key );
00094         value = line.substr( equals_sign_index + 1 );
00095 
00096         // Store the key,value pair if the key is not empty.
00097         if( key.size() > 0 )
00098         {
00099           if( current_dir.size() > 0 )
00100           {
00101             key = current_dir + '/' + key;
00102           }
00103           set( key, value );
00104         }
00105       }
00106     }
00107   }
00108 }
00109 
00110 void Config::write( std::ostream& output )
00111 {
00112   std::string last_prefix;
00113   std::string key_tail;
00114   std::string key_prefix;
00115 
00116   for( Iterator it = begin(); it != end(); it++ )
00117   {
00118     const std::string& key = (*it).first;
00119     const std::string& value = (*it).second;
00120     size_t last_slash_index = key.find_last_of( '/' );
00121     if( last_slash_index == std::string::npos )
00122     {
00123       key_tail = key;
00124       key_prefix = "";
00125     }
00126     else
00127     {
00128       key_tail = key.substr( last_slash_index + 1 );
00129       key_prefix = key.substr( 0, last_slash_index );
00130     }
00131     if( key_prefix != last_prefix )
00132     {
00133       writeDirectory( output, key_prefix, last_prefix );
00134     }
00135     key_tail = escapeKey( key_tail );
00136     output << key_tail << "=" << value << std::endl;
00137     last_prefix = key_prefix;
00138   }
00139 }
00140 
00141 // Write a directory description of new_dir to output, given that
00142 // we were previously "in" prev_dir.  For example:
00143 //
00144 // new_dir = a/c, prev_dir = a/b/z, output:
00145 //   [a/c]
00146 //
00147 // new_dir = a/c, prev_dir = a, output:
00148 //   [a/c]
00149 //
00150 // new_dir = a/c, prev_dir = "", output:
00151 //   [a]
00152 //   [a/c]
00153 //
00154 // new_dir = a/c, prev_dir = "b", output:
00155 //   [a]
00156 //   [a/c]
00157 //
00158 // new_dir = a/b/c, prev_dir = "a", output:
00159 //   [a/b]
00160 //   [a/b/c]
00161 //
00162 // new_dir = a/b/c, prev_dir = "a/z/y", output:
00163 //   [a/b]
00164 //   [a/b/c]
00165 void Config::writeDirectory( std::ostream& output, const std::string& new_dir, const std::string& prev_dir )
00166 {
00167   // Find common initial substring between new_dir and prev_dir
00168   size_t min_size = new_dir.size() < prev_dir.size() ? new_dir.size() : prev_dir.size();
00169 
00170   size_t index = 0; // index of first non-matching char.
00171   for( ; index < min_size; index++ )
00172   {
00173     if( new_dir[ index ] != prev_dir[ index ] )
00174     {
00175       break;
00176     }
00177   }
00178 
00179   // If we are pointed at a '/' move just past it.
00180   if( index < new_dir.size() && new_dir[ index ] == '/' )
00181   {
00182     index++;
00183   }
00184 
00185   // Search forward for first '/' after the matching part.  That will
00186   // be the end of the first string we need to print.
00187   bool done = false;
00188   while( !done )
00189   {
00190     index = new_dir.find_first_of( '/', index );
00191     if( index == std::string::npos )
00192     {
00193       index = new_dir.size();
00194       done = true;
00195     }
00196     output << '[' << new_dir.substr( 0, index ) << ']' << std::endl;
00197     index++; // Skip the '/'
00198   }
00199 }
00200 
00201 std::string Config::escapeKey( const std::string& raw_key )
00202 {
00203   std::istringstream in( raw_key );
00204   std::ostringstream out;
00205   char c;
00206   while( in.good() )
00207   {
00208     c = in.get();
00209     if( in )
00210     {
00211       switch( c )
00212       {
00213       case ':':
00214       case ' ':
00215       case '\\':
00216         out << '\\';
00217       }
00218       out << c;
00219     }
00220   }
00221   return out.str();
00222 }
00223 
00224 std::string Config::unescapeKey( const std::string& cooked_key )
00225 {
00226   std::istringstream in( cooked_key );
00227   std::ostringstream out;
00228   char c;
00229   while( in.good() )
00230   {
00231     c = in.get();
00232     if( in.good() )
00233     {
00234       if( c == '\\' )
00235       {
00236         c = in.get();
00237         if( in.good() )
00238         {
00239           out << c;
00240         }
00241       }
00242       else
00243       {
00244         out << c;
00245       }
00246     }
00247   }
00248   return out.str();
00249 }
00250 
00251 void Config::set( const std::string& key, float value )
00252 {
00253   std::stringstream ss;
00254   ss << value;
00255   map_[ stripFirstSlash( key )] = ss.str();
00256 }
00257 
00258 void Config::set( const std::string& key, int value )
00259 {
00260   std::stringstream ss;
00261   ss << value;
00262   map_[ stripFirstSlash( key )] = ss.str();
00263 }
00264 
00265 bool Config::get( const std::string& key, std::string* output, const std::string& default_value )
00266 {
00267   Iterator it = map_.find( stripFirstSlash( key ));
00268   if( it != map_.end() )
00269   {
00270     *output = (*it).second;
00271     return true;
00272   }
00273   *output = default_value;
00274   return false;
00275 }
00276 
00277 bool Config::get( const std::string& key, float* output, float default_value )
00278 {
00279   Iterator it = map_.find( stripFirstSlash( key ));
00280   if( it != map_.end() )
00281   {
00282     std::istringstream iss;
00283     iss.str( (*it).second );
00284     iss >> *output;
00285     if( !iss.fail() )
00286     {
00287       return true;
00288     }
00289   }
00290   *output = default_value;
00291   return false;
00292 }
00293 
00294 bool Config::get( const std::string& key, int* output, int default_value )
00295 {
00296   Iterator it = map_.find( stripFirstSlash( key ));
00297   if( it != map_.end() )
00298   {
00299     std::istringstream iss;
00300     iss.str( (*it).second );
00301     iss >> *output;
00302     if( !iss.fail() )
00303     {
00304       return true;
00305     }
00306   }
00307   *output = default_value;
00308   return false;
00309 }
00310 
00311 const std::string Config::stripFirstSlash( const std::string& str )
00312 {
00313   if( str[0] == '/' )
00314   {
00315     return str.substr( 1 );
00316   }
00317   else
00318   {
00319     return str;
00320   }
00321 }
00322 
00323 bool Config::DirectoryCompare::operator() (const std::string& lhs, const std::string& rhs) const
00324 {
00325   int start = 0;
00326   int count;
00327   int rhs_count;
00328   size_t l_slash_index, r_slash_index;
00329   bool l_on_last, r_on_last;
00330 
00331   // Loop once for each section of the strings (where sections are
00332   // delimited by '/' characters) as long as the corresponding
00333   // sections are equal.  When we come to a section in which lhs !=
00334   // rhs, return either true or false.
00335   while( true )
00336   {
00337     // Find the index of the next slash in each string, if there is one.
00338     l_slash_index = lhs.find_first_of( '/', start );
00339     r_slash_index = rhs.find_first_of( '/', start );
00340     l_on_last = ( l_slash_index == std::string::npos );
00341     if( l_on_last )
00342     {
00343       l_slash_index = lhs.size();
00344     }
00345     r_on_last = ( r_slash_index == std::string::npos );
00346     if( r_on_last )
00347     {
00348       r_slash_index = rhs.size();
00349     }
00350 
00351     // If one but not both of the strings is on the last section, we
00352     // know the result.  A string which is on its last element is
00353     // "less" than a string which has more elements coming, regardless
00354     // of the current-element comparison.
00355     if( !l_on_last && r_on_last )
00356     {
00357       return false;
00358     }
00359     if( l_on_last && !r_on_last )
00360     {
00361       return true;
00362     }
00363 
00364     // Update the comparison lengths.
00365     count = l_slash_index - start;
00366     rhs_count = r_slash_index - start;
00367 
00368     // Compare the current section of each string.
00369     int result = lhs.compare( start, count, rhs, start, rhs_count );
00370 
00371     // If the sections differ, return true or false according to the
00372     // direction of difference.
00373     if( result != 0 )
00374     {
00375       return result < 0;
00376     }
00377 
00378     // The sections are equal, so if the rhs is ending, then the rhs
00379     // is less, so return false.
00380     if( start + rhs_count >= (int)rhs.size() )
00381     {
00382       return false;
00383     }
00384 
00385     // Move start index to the next section, skipping over the '/'
00386     // character with the +1.
00387     start += count + 1;
00388 
00389     // The sections are equal, so if the lhs is ending, it is less, so
00390     // return true.
00391     if( start > (int)lhs.size() )
00392     {
00393       return true;
00394     }
00395   }
00396 }
00397 
00398 } // end namespace rviz


rviz_qt
Author(s): Dave Hershberger
autogenerated on Fri Dec 6 2013 20:56:52