00001 #ifndef DVUTIL_PROPS_H 00002 #define DVUTIL_PROPS_H 00003 // $Id: props.h,v 1.42 2008/08/28 13:57:02 dvermeir Exp $ 00004 00005 #include <dvutil/stringmap.h> 00006 00007 namespace Dv { 00008 /** 00009 * Storing elements in a Props object: 00010 * 00011 * @code 00012 * props[key] = value; 00013 * @endcode 00014 * 00015 * where key and value can be of any type that can be 00016 * converted to a string using Dv::tostring. 00017 * 00018 * Retrieving can be done in 2 ways: 00019 * using @a operator[] 00020 * @code 00021 * props[key].get<T>() // convert string to type T 00022 * int i = props[key]; // conversion to int will be inferred 00023 * std::cout << props[key]; // string will be printed 00024 * @endcode 00025 * and using @a operator() which works also with 'const' props objects 00026 * @code 00027 * props(key) = 3 // will not compile 00028 * props(key).get<T>() // same as above but props can be const 00029 * int i = props(key) // same as above but props can be const 00030 * std::cout << props(key); // string will be printed 00031 * @endcode 00032 */ 00033 class Props: public StringMap<std::string> { 00034 public: 00035 Props() {} 00036 Props(std::istream& is) { read(is, -1); } 00037 00038 friend std::istream& operator>>(std::istream& is, Props& props) { 00039 return props.read(is, -1); 00040 } 00041 00042 00043 friend std::ostream& operator<<(std::ostream& is, const Props& props); 00044 00045 std::istream& read(std::istream& is, int n); 00046 00047 class Reference { 00048 public: 00049 bool defined() const { return ( props_.find(key_) != 0 ); } 00050 Reference(const std::string& key, Props& props): key_(key), props_(props) {} 00051 Reference(const std::string& key, const Props& props): key_(key), 00052 props_(const_cast<Props&>(props)) { } 00053 00054 template<typename T> 00055 T get() const { 00056 const std::string* s = props_.find(key_); 00057 if (! s) 00058 throw std::domain_error("Dv::Props::get[" + key_ + "]: undefined"); 00059 return fromstring<T>(*s); 00060 } 00061 00062 template<typename T> 00063 T get(const T& default_value) const { 00064 const std::string* s = props_.find(key_); 00065 if (s) 00066 return fromstring<T>(*s); 00067 else 00068 return default_value; 00069 } 00070 00071 std::string get(const char* default_value) const { 00072 const std::string* s = props_.find(key_); 00073 if (s) 00074 return *s; 00075 else 00076 return default_value; 00077 } 00078 00079 std::string str() const { return get<std::string>(); } 00080 00081 template<typename T> 00082 operator T() const { return get<T>(); } 00083 00084 /** Return a reference to the raw string content associated with 00085 * a key. 00086 * @return a reference to the raw string associated with the Reference's key. 00087 * @warning Creates the element associated with the key, if it does not yet exist 00088 */ 00089 operator std::string&() { 00090 return props_.map_.insert(std::make_pair(key_, "")).first->second; 00091 } 00092 00093 operator const std::string&() const { 00094 Props::Map::iterator i = props_.map_.find(key_); 00095 if (i == props_.map_.end()) 00096 throw std::domain_error("Dv::Props::string_ref[" + key_ + "]: undefined"); 00097 return i->second; 00098 } 00099 00100 template<typename T> 00101 Reference& operator=(const T& t) { props_.set(key_, Dv::tostring(t)); return *this; }; 00102 00103 template<typename T> 00104 Reference& operator+=(const T& t) { append(t, " "); return *this; } 00105 00106 template<typename T> 00107 Reference& append(const T& t, const std::string& separator) { 00108 Props::Map::iterator i = props_.map_.find(key_); 00109 if (i == props_.end() ) 00110 (*this) = t; 00111 else 00112 ( i->second += separator ) += Dv::tostring(t); 00113 return *this; 00114 } 00115 00116 Reference& erase() { props_.erase(key_); return *this; } 00117 00118 00119 friend std::ostream& operator<<(std::ostream& os, const Reference& i) { 00120 return os << i.get<std::string>(); 00121 } 00122 00123 template<typename T> 00124 friend 00125 const Props& operator>>(const Reference& r, T& t) { 00126 t = r.get<T>(); 00127 return r.props_; 00128 } 00129 00130 private: 00131 std::string key_; 00132 Props& props_; 00133 friend class Props; 00134 }; 00135 00136 /** Supports "reading" key values from a Props object. 00137 * @code 00138 * Dv::Props props; 00139 * std::string name 00140 * int i; 00141 * Props >> "name" >> name >> "int" >> i; 00142 * @endcode 00143 * @see Props::Reference::operator>> 00144 */ 00145 friend Reference operator>>(const Props& props, const std::string& key) { 00146 return Reference(key, props); 00147 } 00148 00149 template<typename K> 00150 Reference operator[](const K& key) { 00151 return Reference(Dv::tostring(key), *this); 00152 } 00153 00154 template<typename K> 00155 const Reference operator()(const K& key) const { 00156 return Reference(Dv::tostring(key), *this); 00157 } 00158 00159 bool operator==(const Props& props) { return map_ == props.map_; } 00160 bool operator!=(const Props& props) { return ! ( *this == props ); } 00161 00162 /** Load all @a key-value pairs from another props object under a certain 00163 * scope. 00164 * All key-value pairs from @a source will be added to @a *this, 00165 * where the key will be prefixed with <tt>scope::</tt> if the size 00166 * of @a scope is not zero. 00167 * 00168 * Example usage: 00169 * @code 00170 * Props dbconfig; 00171 * Props config; 00172 * config.merge(dbconfig,"database"); 00173 * @endcode 00174 * 00175 * If <tt>dbconfig["name"]=="admindb"</tt> then 00176 * <tt>config["database::name"]=="admindb"</tt> after the merge. 00177 * 00178 * @param source the Props object from which @a key=value pairs will 00179 * be copied. 00180 * @param scope only @a key=value pairs where @a key starts with @a scope:: 00181 * will be copied. 00182 * @return reference to @a *this. 00183 * @warning @a &source must be different from @a this. 00184 * @see Dv::Props::select 00185 */ 00186 Props& merge(const Props& source,const std::string& scope="") throw (std::logic_error); 00187 00188 /** 00189 * Insert selected @a subkey=value pairs of this object into the target. 00190 * The selected pairs are those for which the @a key starts with 00191 * the @a scope std::string followed by '@a ::'. The pairs will be inserted 00192 * with a @a key consisting of the remainder of the original key, 00193 * after removing the @a scope std::string and '::'. 00194 * 00195 * Example. 00196 * @code 00197 * Props config; 00198 * Props dbconfig; 00199 * config.select("database",dbconfig); 00200 * @endcode 00201 * 00202 * In the example, if <tt>config["database::name"] == "admindb"</tt> 00203 * then <tt>dbconfig["name"] == "admindb"</tt> after the call to 00204 * <tt>select</tt>. 00205 * 00206 * The function returns a reference to its second first argument. 00207 * 00208 * @param target the Props object the selected pairs will be added to. 00209 * @param scope the selected pairs have ``<tt>scope::</tt>'' as a key. 00210 * @return a reference to @a target. 00211 */ 00212 Props& select(const std::string& scope, Props& target) const; 00213 00214 /** 00215 * Recursively substitute variable occurrences in sin to yield sout. 00216 * @param sin stream that is appended to @a sout. 00217 * @param sout stream that is appended to. 00218 * @param f function that transforms strings. ${name} 00219 * in @a sin is replaced by @a f((*this)[name]). 00220 * @exception invalid_argument is thrown upon a syntax error. 00221 * 00222 * Sin is a stream, the contents which is appended to sout except for variable 00223 * occurrences of the form ${key} or %{key} which 00224 * are replaced by @a f((*this)[key]) and @a (*this)[key], 00225 * respectively (the ``$'' sign can be escaped using ``\''). 00226 * 00227 * Undefined (in *this) variables are replaced by the empty std::string. 00228 * 00229 * Example: 00230 * @code 00231 * std::string query("select * from"); 00232 * props.substitute("person where name = '${name}' and age = %{age}", query, MySql::escape); 00233 * @endcode 00234 * 00235 * Syntax: 00236 * <ul> 00237 * <li> Variables start with ``${'' or ``%{'' except if the 00238 * ``$'' or ``%'' is preceeded by a backslash (``@''). 00239 * <li> A backslash is a normal character, except if it 00240 * is immediately followed by a ``$'' or a ``%'', in which 00241 * case it is not copied. 00242 * </ul> 00243 */ 00244 void substitute(std::istream& sin,std::ostream& sout, 00245 std::string (*f)(const std::string&) = 0) const throw (std::invalid_argument); 00246 /** 00247 * Recursively substitute variable occurrences in sin to yield sout. 00248 * 00249 * @param sin std::string that is appended to @a sout. 00250 * @param sout std::string that is appended to. 00251 * @param f function that transforms strings. ${name} 00252 * in @a sin is replaced by @a f((*this)[name]). 00253 * @exception invalid_argument is thrown upon a syntax error. 00254 * 00255 * Sin is a std::string which is appended to sout except for variable 00256 * occurrences of the form ${key} or %{key} which 00257 * are replaced by @a f((*this)[key]) and @a (*this)[key], 00258 * respectively (the ``$'' sign can be escaped using ``\''). 00259 * 00260 * Undefined (in @a *this) variables are replaced by the empty std::string. 00261 * 00262 * Syntax: 00263 * <ul> 00264 * <li> Variables start with ``${'' or ``%{'' except if the 00265 * ``$'' or ``%'' is preceeded by a backslash (``@''). 00266 * <li> A backslash is a normal character, except if it 00267 * is immediately followed by a ``$'' or a ``%'', in which 00268 * case it is not copied. 00269 * </ul> 00270 */ 00271 void substitute(const std::string& sin, std::string& sout, 00272 std::string (*f)(const std::string&) = 0) const throw (std::invalid_argument); 00273 /** Same as above but returns result std::string. 00274 * @param sin std::string that is appended to return value. 00275 * @param f function that transforms strings. ${name} 00276 * in @a sin is replaced by @a f((*this)[name]). 00277 * @return std::string with subsitutions performed. 00278 * @exception invalid_argument is thrown upon a syntax error. 00279 * @see Props::substitute 00280 */ 00281 std::string substitute(const std::string& sin, std::string (*f)(const std::string&) = 0) 00282 const throw (std::invalid_argument); 00283 }; 00284 00285 Props& env2props(Props& props); 00286 00287 } 00288 #endif
dvutil-1.0.10 | [ 5 December, 2009] |