libmoost
/home/mhx/git/github/libmoost/src/configurable/binder.cpp
Go to the documentation of this file.
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 }