IBR-DTNSuite  0.10
ConfigFile.h
Go to the documentation of this file.
1 /*
2  * ConfigFile.h
3  *
4  * Class for reading named values from configuration files
5  * Richard J. Wagner v2.1 24 May 2004 wagnerr@umich.edu
6  *
7  * Copyright (c) 2004 Richard J. Wagner
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to
11  * deal in the Software without restriction, including without limitation the
12  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13  * sell copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25  * IN THE SOFTWARE.
26  *
27  * Typical usage
28  * -------------
29  *
30  * Given a configuration file "settings.inp":
31  * atoms = 25
32  * length = 8.0 # nanometers
33  * name = Reece Surcher
34  *
35  * Named values are read in various ways, with or without default values:
36  * ConfigFile config( "settings.inp" );
37  * int atoms = config.read<int>( "atoms" );
38  * double length = config.read( "length", 10.0 );
39  * string author, title;
40  * config.readInto( author, "name" );
41  * config.readInto( title, "title", string("Untitled") );
42  *
43  * See file example.cpp for more examples.
44  */
45 
46 #ifndef IBRCOMMON_CONFIGFILE_H
47 #define IBRCOMMON_CONFIGFILE_H
48 
49 #include <string>
50 #include <map>
51 #include <iostream>
52 #include <fstream>
53 #include <sstream>
54 
55 using std::string;
56 
57 namespace ibrcommon
58 {
59  class ConfigFile {
60  // Data
61  protected:
62  string myDelimiter; // separator between key and value
63  string myComment; // separator between value and comments
64  string mySentry; // optional string to signal end of file
65  std::map<string,string> myContents; // extracted keys and values
66 
67  typedef std::map<string,string>::iterator mapi;
68  typedef std::map<string,string>::const_iterator mapci;
69 
70  // Methods
71  public:
72  ConfigFile( string filename,
73  string delimiter = "=",
74  string comment = "#",
75  string sentry = "EndConfigFile" );
76  ConfigFile();
77 
78  // Search for key and read value or optional default value
79  template<class T> T read( const string& key ) const; // call as read<T>
80  template<class T> T read( const string& key, const T& value ) const;
81  template<class T> bool readInto( T& var, const string& key ) const;
82  template<class T>
83  bool readInto( T& var, const string& key, const T& value ) const;
84 
85  // Modify keys and values
86  template<class T> void add( string key, const T& value );
87  void remove( const string& key );
88 
89  // Check whether key exists in configuration
90  bool keyExists( const string& key ) const;
91 
92  // Check or change configuration syntax
93  string getDelimiter() const { return myDelimiter; }
94  string getComment() const { return myComment; }
95  string getSentry() const { return mySentry; }
96  string setDelimiter( const string& s )
97  { string old = myDelimiter; myDelimiter = s; return old; }
98  string setComment( const string& s )
99  { string old = myComment; myComment = s; return old; }
100 
101  // Write or read configuration
102  friend std::ostream& operator<<( std::ostream& os, const ConfigFile& cf );
103  friend std::istream& operator>>( std::istream& is, ConfigFile& cf );
104 
105  protected:
106  template<class T> static string T_as_string( const T& t );
107  template<class T> static T string_as_T( const string& s );
108  static void trim( string& s );
109 
110 
111  // Exception types
112  public:
113  struct file_not_found {
114  string filename;
115  file_not_found( const string& filename_ = string() )
116  : filename(filename_) {} };
117  struct key_not_found { // thrown only by T read(key) variant of read()
118  string key;
119  key_not_found( const string& key_ = string() )
120  : key(key_) {} };
121  };
122 
123 
124  /* static */
125  template<class T>
126  string ConfigFile::T_as_string( const T& t )
127  {
128  // Convert from a T to a string
129  // Type T must support << operator
130  std::ostringstream ost;
131  ost << t;
132  return ost.str();
133  }
134 
135 
136  /* static */
137  template<class T>
138  T ConfigFile::string_as_T( const string& s )
139  {
140  // Convert from a string to a T
141  // Type T must support >> operator
142  T t;
143  std::istringstream ist(s);
144  ist >> t;
145  return t;
146  }
147 
148 
149  /* static */
150  template<>
151  inline string ConfigFile::string_as_T<string>( const string& s )
152  {
153  // Convert from a string to a string
154  // In other words, do nothing
155  return s;
156  }
157 
158 
159  /* static */
160  template<>
161  inline bool ConfigFile::string_as_T<bool>( const string& s )
162  {
163  // Convert from a string to a bool
164  // Interpret "false", "F", "no", "n", "0" as false
165  // Interpret "true", "T", "yes", "y", "1", "-1", or anything else as true
166  bool b = true;
167  string sup = s;
168  for( string::iterator p = sup.begin(); p != sup.end(); ++p )
169  *p = static_cast<char>(toupper(*p)); // make string all caps
170  if( sup==string("FALSE") || sup==string("F") ||
171  sup==string("NO") || sup==string("N") ||
172  sup==string("0") || sup==string("NONE") )
173  b = false;
174  return b;
175  }
176 
177 
178  template<class T>
179  T ConfigFile::read( const string& key ) const
180  {
181  // Read the value corresponding to key
182  mapci p = myContents.find(key);
183  if( p == myContents.end() ) throw key_not_found(key);
184  return string_as_T<T>( p->second );
185  }
186 
187 
188  template<class T>
189  T ConfigFile::read( const string& key, const T& value ) const
190  {
191  // Return the value corresponding to key or given default value
192  // if key is not found
193  mapci p = myContents.find(key);
194  if( p == myContents.end() ) return value;
195  return string_as_T<T>( p->second );
196  }
197 
198 
199  template<class T>
200  bool ConfigFile::readInto( T& var, const string& key ) const
201  {
202  // Get the value corresponding to key and store in var
203  // Return true if key is found
204  // Otherwise leave var untouched
205  mapci p = myContents.find(key);
206  bool found = ( p != myContents.end() );
207  if( found ) var = string_as_T<T>( p->second );
208  return found;
209  }
210 
211 
212  template<class T>
213  bool ConfigFile::readInto( T& var, const string& key, const T& value ) const
214  {
215  // Get the value corresponding to key and store in var
216  // Return true if key is found
217  // Otherwise set var to given default
218  mapci p = myContents.find(key);
219  bool found = ( p != myContents.end() );
220  if( found )
221  var = string_as_T<T>( p->second );
222  else
223  var = value;
224  return found;
225  }
226 
227 
228  template<class T>
229  void ConfigFile::add( string key, const T& value )
230  {
231  // Add a key with given value
232  string v = T_as_string( value );
233  trim(key);
234  trim(v);
235  myContents[key] = v;
236  return;
237  }
238 }
239 
240 #endif // CONFIGFILE_H
241 
242 // Release notes:
243 // v1.0 21 May 1999
244 // + First release
245 // + Template read() access only through non-member readConfigFile()
246 // + ConfigurationFileBool is only built-in helper class
247 //
248 // v2.0 3 May 2002
249 // + Shortened name from ConfigurationFile to ConfigFile
250 // + Implemented template member functions
251 // + Changed default comment separator from % to #
252 // + Enabled reading of multiple-line values
253 //
254 // v2.1 24 May 2004
255 // + Made template specializations inline to avoid compiler-dependent linkage
256 // + Allowed comments within multiple-line values
257 // + Enabled blank line termination for multiple-line values
258 // + Added optional sentry to detect end of configuration file
259 // + Rewrote messy trimWhitespace() function as elegant trim()