libmoost
|
00001 /* vim:set ts=3 sw=3 sts=3 et: */ 00028 #include "../../include/moost/configurable/binder.h" 00029 00030 #include <sstream> 00031 #include <stdexcept> 00032 #include <set> 00033 00034 using namespace boost; 00035 using namespace moost::configurable; 00036 00037 binder::~binder() 00038 { 00039 for (std::vector<persistable *>::iterator it = m_bindings.begin(); it != m_bindings.end(); ++it) 00040 delete *it; 00041 } 00042 00043 void binder::child(const std::string & key, persistable & value) 00044 { 00045 m_routes[key] = &value; 00046 } 00047 00049 void binder::read(std::istream & source) 00050 { 00051 // first, read { 00052 std::string token; 00053 00054 source >> token; 00055 00056 if (token != "{") 00057 throw std::runtime_error("bad token: '" + token + "', expecting '}'"); 00058 00059 // any route that doesn't read, we must set the default 00060 std::set< std::string > found_routes; 00061 00062 for (;;) 00063 { 00064 source >> token; 00065 00066 if (token == "}") 00067 break; 00068 00069 if (source.eof()) 00070 throw std::runtime_error("unexpected eof, expecting '}'"); 00071 00072 route_map::iterator it = m_routes.find(token); 00073 00074 if (it == m_routes.end()) 00075 throw std::runtime_error("no route for token: '" + token + "'"); 00076 00077 found_routes.insert(it->first); 00078 00079 source.get(); // skip past the ' ' 00080 try 00081 { 00082 it->second->read(source); 00083 } 00084 catch (const std::runtime_error & e) 00085 { 00086 throw std::runtime_error(it->first + ": " + e.what()); 00087 } 00088 } 00089 00090 // set defaults for any remaining routes 00091 for (route_map::iterator it = m_routes.begin(); it != m_routes.end(); ++it) 00092 { 00093 if (found_routes.find(it->first) == found_routes.end()) 00094 { 00095 try 00096 { 00097 it->second->set_default(); 00098 } 00099 catch (const std::runtime_error & e) 00100 { 00101 throw std::runtime_error(it->first + ": " + e.what()); 00102 } 00103 } 00104 } 00105 } 00106 00108 void binder::write(std::ostream & dest, int indent /* = 0 */) const 00109 { 00110 // new context always means new indent 00111 indent += configurable::DEFAULT_INDENT; 00112 00113 // first, write { 00114 dest << '{' << std::endl; 00115 for (int i = 0; i != indent; ++i) 00116 dest << ' '; 00117 00118 for (route_map::const_iterator it = m_routes.begin(); it != m_routes.end(); ++it) 00119 { 00120 dest << it->first << ' '; 00121 it->second->write(dest, indent); 00122 dest << std::endl; 00123 for (int i = 0; i != indent; ++i) 00124 dest << ' '; 00125 } 00126 00127 dest.seekp(-configurable::DEFAULT_INDENT, std::ios::cur); 00128 dest << '}'; 00129 } 00130 00132 void binder::set(const std::string & key, const std::string & value) 00133 { 00134 route_map::iterator it = m_routes.find(key); 00135 00136 size_t n = key.size(); 00137 for ( ; it == m_routes.end(); ) 00138 { 00139 n = key.rfind('.', n - 1); 00140 if (n == 0 || n == std::string::npos) 00141 throw std::runtime_error("no route for key: '" + key + "'"); 00142 it = m_routes.find(key.substr(0, n)); 00143 } 00144 00145 if (n != key.size()) 00146 { 00147 configurable * p = dynamic_cast<configurable *>(it->second); 00148 if (!p) 00149 throw std::runtime_error("no route for key: '" + key + "'"); 00150 p->set(key.substr(n + 1, key.size() - n - 1), value); 00151 } 00152 else 00153 { 00154 std::istringstream iss(value); 00155 it->second->read(iss); 00156 } 00157 } 00158 00160 void binder::get(const std::string & key, std::string & value) const 00161 { 00162 route_map::const_iterator it = m_routes.find(key); 00163 00164 size_t n = key.size(); 00165 for (; it == m_routes.end(); ) 00166 { 00167 n = key.rfind('.', n - 1); 00168 if (n == 0 || n == std::string::npos) 00169 throw std::runtime_error("no route for key: '" + key + "'"); 00170 it = m_routes.find(key.substr(0, n)); 00171 } 00172 00173 if (n != key.size()) 00174 { 00175 configurable * p = dynamic_cast<configurable *>(it->second); 00176 if (!p) 00177 throw std::runtime_error("no route for key: '" + key + "'"); 00178 p->get(key.substr(n + 1, key.size() - n - 1), value); 00179 } 00180 else 00181 { 00182 std::ostringstream oss; 00183 it->second->write(oss); 00184 value = oss.str(); 00185 } 00186 } 00187 00188 void binder::list(std::vector< std::pair< std::string, std::string > > & items) 00189 { 00190 for (route_map::iterator it = m_routes.begin(); it != m_routes.end(); ++it) 00191 { 00192 configurable * p = dynamic_cast<configurable *>(it->second); 00193 if (p) 00194 { 00195 std::vector< std::pair< std::string, std::string > > sub_items; 00196 p->list(sub_items); 00197 for (std::vector< std::pair< std::string, std::string > >::const_iterator it_s = sub_items.begin(); it_s != sub_items.end(); ++it_s) 00198 items.push_back(std::make_pair(it->first + '.' + it_s->first, it_s->second)); 00199 } 00200 else 00201 { 00202 std::ostringstream oss; 00203 it->second->write(oss); 00204 items.push_back(std::make_pair(it->first, oss.str())); 00205 } 00206 } 00207 } 00208 00209 void binder::set_default() 00210 { 00211 for (route_map::iterator it = m_routes.begin(); it != m_routes.end(); ++it) 00212 { 00213 try 00214 { 00215 it->second->set_default(); 00216 } 00217 catch (const std::runtime_error &) 00218 { 00219 throw std::runtime_error(it->first + ": cannot set default"); 00220 } 00221 } 00222 00223 }