46 readFrom( path , utf8 ) ;
52 G_LOG(
"MapFile::read: start" ) ;
53 readFrom( stream , utf8 ) ;
60 m_keys.reserve( m_map.size() ) ;
61 for( StringMap::iterator p = m_map.begin() ; p != m_map.end() ; ++p )
62 m_keys.push_back( (*p).first ) ;
68 for( OptionMap::const_iterator p = map.
begin() ; p != map.
end() ; )
70 std::string key = (*p).first ;
73 std::string
value = (*p).second.valued() ? map.
value(key) : yes ;
77 while( p != map.
end() && (*p).first == key )
82 void G::MapFile::readFrom(
const G::Path & path ,
bool utf8 )
84 std::ifstream stream( path.
str().c_str() ) ;
86 throw std::runtime_error( std::string() +
"cannot open \"" + path.
str() +
"\"" ) ;
87 G_LOG(
"MapFile::read: reading [" << path.
str() <<
"]" ) ;
88 readFrom( stream , utf8 ) ;
91 void G::MapFile::readFrom( std::istream & ss ,
bool utf8 )
102 std::string::size_type pos_interesting = line.find_first_not_of(
" \t\r#") ;
103 if( pos_interesting == std::string::npos )
106 std::string::size_type pos_hash = line.find(
"#") ;
107 if( pos_hash != std::string::npos && pos_hash < pos_interesting )
112 if( part.size() == 0U )
115 std::string value = part.size() == 1U ? std::string() : line.substr(part[0].length()+1U) ;
117 if( value.length() >= 2U && value.at(0U) ==
'"' && value.at(value.length()-1U) ==
'"' )
118 value = value.substr(1U,value.length()-2U) ;
120 std::string key = part[0] ;
123 value = fromUtf( value , utf8 ) ;
132 tmp.m_logging = false ;
133 tmp.readFrom( path , utf8 ) ;
138 for( StringArray::const_iterator p = m_keys.begin() ; p != m_keys.end() ; ++p )
139 log( (*(m_map.find(*p))).first , (*(m_map.find(*p))).second ) ;
142 void G::MapFile::log(
const std::string & key ,
const std::string & value )
const
144 log( m_logging , key , value ) ;
147 void G::MapFile::log(
bool logging ,
const std::string & key ,
const std::string & value )
150 G_LOG(
"MapFile::item: " << key <<
"=[" <<
151 ( key.find(
"password") == std::string::npos ?
153 std::string(
"<not-logged>")
159 std::string value = m_map.find(key) == m_map.end() ? std::string() : (*m_map.find(key)).second ;
160 writeItem( stream , key , value , utf8 ) ;
163 void G::MapFile::writeItem( std::ostream & stream ,
const std::string & key ,
const std::string & value ,
bool utf8 )
165 log(
true , key , value ) ;
166 const char * qq = value.find(
' ') == std::string::npos ?
"" :
"\"" ;
167 stream << key <<
"=" << qq << toUtf(value,utf8) << qq <<
"\n" ;
170 std::string G::MapFile::quote(
const std::string & s )
172 return s.find_first_of(
" \t") == std::string::npos ? s : (std::string()+
"\""+s+
"\"") ;
177 typedef std::list<std::string> List ;
178 List lines = read( path , allow_read_error ) ;
179 commentOut( lines ) ;
180 replace( lines , utf8 ) ;
181 if( make_backup ) backup( path ) ;
182 save( path , lines , allow_write_error ) ;
185 G::MapFile::List G::MapFile::read(
const G::Path & path ,
bool allow_read_error )
const
188 std::ifstream file_in( path.
str().c_str() ) ;
189 if( !file_in.good() && !allow_read_error )
190 throw std::runtime_error( std::string() +
"cannot read \"" + path.
str() +
"\"" ) ;
191 while( file_in.good() )
194 if( !file_in ) break ;
195 line_list.push_back( line ) ;
200 void G::MapFile::commentOut( List & line_list )
const
202 for( List::iterator line_p = line_list.begin() ; line_p != line_list.end() ; ++line_p )
204 std::string & line = *line_p ;
205 if( line.empty() || line.at(0U) ==
'#' )
207 line = std::string(1U,
'#') + line ;
211 void G::MapFile::replace( List & line_list ,
bool utf8 )
const
213 for( StringMap::const_iterator map_p = m_map.begin() ; map_p != m_map.end() ; ++map_p )
216 for( List::iterator line_p = line_list.begin() ; line_p != line_list.end() ; ++line_p )
218 std::string & line = (*line_p) ;
219 if( line.empty() )
continue ;
222 if( part.size() == 0U )
continue ;
223 if( part.at(0U) == (*map_p).first )
225 std::string value = toUtf( (*map_p).second , utf8 ) ;
234 std::string value = toUtf( (*map_p).second , utf8 ) ;
240 void G::MapFile::backup(
const G::Path & path )
244 std::string timestamp = Date(now).string(Date::yyyy_mm_dd) + Time(now).hhmmss() ;
246 Process::Umask umask( Process::Umask::Tightest ) ;
247 File::copy( path , backup , File::NoThrow() ) ;
250 void G::MapFile::save(
const G::Path & path , List & line_list ,
bool allow_write_error )
252 std::ofstream file_out( path.
str().c_str() , std::ios_base::out | std::ios_base::trunc ) ;
253 std::copy( line_list.begin() , line_list.end() , std::ostream_iterator<std::string>(file_out,
"\n") ) ;
255 if( file_out.fail() && !allow_write_error )
256 throw std::runtime_error( std::string() +
"cannot write \"" + path.
str() +
"\"" ) ;
261 StringMap::const_iterator p = m_map.find( key ) ;
262 std::string result = ( p == m_map.end() || (*p).second.empty() ) ? default_ : (*p).second ;
268 return value( key , std::string(default_) ) ;
271 std::string G::MapFile::mandatoryValue(
const std::string & key )
const
273 if( m_map.find(key) == m_map.end() )
274 throw std::runtime_error( std::string() +
"cannot find config item \"" + key +
"\"" ) ;
275 return value( key ) ;
280 return Path( mandatoryValue(key) ) ;
285 return Path( expand(mandatoryValue(key)) ) ;
290 return Path( value(key,default_.
str()) ) ;
295 return Path( expand(value(key,default_.
str())) ) ;
300 std::string s = value( key , std::string() ) ;
306 std::string s = value( key , default_ ?
"Y" :
"N" ) ;
307 return !s.empty() && ( s.at(0U) ==
'y' || s.at(0U) ==
'Y' ) ;
312 StringMap::iterator p = m_map.find( key ) ;
313 if( p != m_map.end() )
316 G_ASSERT( std::find(m_keys.begin(),m_keys.end(),key) != m_keys.end() ) ;
317 m_keys.erase( std::find(m_keys.begin(),m_keys.end(),key) ) ;
323 std::string value( value_in ) ;
330 size_t find_single( std::string & s ,
char c ,
size_t start_pos )
332 char cc[] = { c ,
'\0' } ;
333 size_t pos = start_pos ;
336 pos = s.find( cc , pos ) ;
337 if( pos == std::string::npos )
341 else if( (pos+1U) < s.length() && s.at(pos+1U) == c )
343 s.erase( pos , 1U ) ;
344 if( (pos+1U) == s.length() )
346 pos = std::string::npos ;
360 bool G::MapFile::expand_( std::string & value )
const
362 bool changed = false ;
365 size_t const npos = std::string::npos ;
366 while( end < value.length() )
368 start = find_single( value ,
'%' , end ) ;
369 if( start == npos ) break ;
370 end = value.find(
"%" , start+1U ) ;
371 if( end == npos ) break ;
373 std::string key = value.substr( start+1U , end-start-2U ) ;
374 StringMap::const_iterator p = m_map.find( key ) ;
375 if( p != m_map.end() )
377 size_t old = end - start ;
378 size_t new_ = (*p).second.length() ;
379 value.replace( start , old , (*p).second ) ;
390 if( m_map.find(key) == m_map.end() )
391 m_keys.push_back( key ) ;
397 return m_map.find( key ) != m_map.end() ;
410 std::string G::MapFile::fromUtf(
const std::string & value ,
bool utf8 )
412 if( G::is_windows() && utf8 )
424 std::string G::MapFile::toUtf(
const std::string & value ,
bool utf8 )
426 if( G::is_windows() && utf8 )
428 Convert::utf8 result ;
void editInto(const G::Path &path, bool make_backup=true, bool allow_read_error=false, bool allow_write_error=false, bool utf8=false) const
Edits an existing file so that its contents reflect this map.
std::string str() const
Returns the path string.
static std::string printable(const std::string &in, char escape= '\\')
Returns a printable represention of the given input string.
static void convert(utf8 &utf_out, const std::string &in_)
Converts between string types/encodings: ansi to utf8.
static bool copy(const Path &from, const Path &to, const NoThrow &)
Copies a file. Returns false on error.
std::string value(const std::string &key, const std::string &default_=std::string()) const
Returns a string value from the map.
std::string basename() const
Returns the rightmost part of the path, ignoring "." parts.
const G::StringArray & keys() const
Returns a reference to the ordered list of keys.
static BrokenDownTime local(EpochTime epoch_time)
Converts from epoch time to local broken-down-time.
std::vector< std::string > StringArray
A std::vector of std::strings.
static void splitIntoTokens(const std::string &in, StringArray &out, const std::string &ws)
Splits the string into 'ws'-delimited tokens.
bool contains(const std::string &) const
Returns true if the map contains the given key, but ignoring un-valued() 'off' options.
const_iterator begin() const
Returns the begin iterator.
std::string value(const std::string &key) const
Returns the value of the valued() option identified by the given key.
Holds context information which convert() adds to the exception when it fails.
void remove(const std::string &key)
Removes a value (if it exists).
static EpochTime now()
Returns the current epoch time.
A map-like container for command-line options and their values.
G::Path pathValue(const std::string &key) const
Returns a mandatory path value from the map. Throws if it does not exist.
bool contains(const std::string &key) const
Returns true if the map contains the given key.
const G::StringMap & map() const
Returns a reference to the internal map.
static unsigned int toUInt(const std::string &s)
Converts string 's' to an unsigned int.
void writeItem(std::ostream &, const std::string &key, bool utf8=false) const
Writes a single item from this map to the stream.
G::Path expandedPathValue(const std::string &key) const
Returns a mandatory path value from the map with expand(). Throws if it does not exist.
A class for reading and editing key=value files, supporting the creation of backup files...
unsigned int numericValue(const std::string &key, unsigned int default_) const
Returns a numeric value from the map.
void add(const std::string &key, const std::string &value)
Adds or updates a single item in the map.
A string wrapper that indicates UTF-8 encoding.
std::string expand(const std::string &value) const
Does one-pass variable substitution for the given string.
const_iterator end() const
Returns the off-the-end iterator.
static std::string trimmed(const std::string &s, const std::string &ws)
Returns a trim()med version of s.
static std::string readLineFrom(std::istream &stream, const std::string &eol=std::string())
Reads a line from the stream using the given line terminator.
Path dirname() const
Returns the path without the rightmost part, ignoring "." parts.
MapFile()
Constructor for an empty map.
bool booleanValue(const std::string &key, bool default_) const
Returns a boolean value from the map.
std::map< std::string, std::string > StringMap
A std::map of std::strings.
static bool isUInt(const std::string &s)
Returns true if the string can be converted into an unsigned integer without throwing an exception...
A Path object represents a file system path.
static std::string ws()
A convenience function returning standard whitespace characters.
static void check(const G::Path &, bool utf8=false)
Throws if the file is invalid.
void log() const
Logs the contents.