Properties.cpp
Go to the documentation of this file.
00001 // -*- C++ -*-
00020 #include <coil/Properties.h>
00021 #include <coil/stringutil.h>
00022 #include <iostream>
00023 
00024 namespace coil
00025 {
00033   Properties::Properties(const char* key, const char* value)
00034     : name(key), value(value), default_value(""), root(NULL), m_empty("")
00035   {
00036     leaf.clear();
00037   }
00038   
00046   Properties::Properties(std::map<std::string, std::string>& defaults)
00047     : name(""), value(""), default_value(""), root(NULL), m_empty("")
00048   {
00049     leaf.clear();
00050     std::map<std::string, std::string>::iterator it(defaults.begin());
00051     std::map<std::string, std::string>::iterator it_end(defaults.end());
00052     
00053     while (it != it_end)
00054       {
00055         setDefault(it->first.c_str(), it->second.c_str());
00056         ++it;
00057       }
00058   }
00059   
00067   Properties::Properties(const char* defaults[], long num)
00068     : name(""), value(""), default_value(""), root(NULL), m_empty("")
00069   {
00070     leaf.clear();
00071     setDefaults(defaults, num);
00072   }
00073   
00081   Properties::Properties(const Properties& prop)
00082     : name(prop.name), value(prop.value),
00083       default_value(prop.default_value), root(NULL), m_empty("")
00084   {
00085     std::vector<std::string> keys;
00086     keys = prop.propertyNames();
00087     for (size_t i(0), len(keys.size()); i < len; ++i)
00088       {
00089         const Properties* node(NULL);
00090         if ((node = prop.findNode(keys[i])) != NULL)
00091           {
00092             setDefault(keys[i],  node->default_value);
00093             setProperty(keys[i], node->value);
00094           }
00095       }
00096   }
00097   
00105   Properties& Properties::operator=(const Properties& prop)
00106   {
00107     clear();
00108     name = prop.name;
00109     value = prop.value;
00110     default_value = prop.default_value;
00111     
00112     std::vector<std::string> keys;
00113     keys = prop.propertyNames();
00114     for (size_t i(0), len(keys.size()); i < len; ++i)
00115       {
00116         const Properties* node(prop.findNode(keys[i]));
00117         if (node != 0)
00118           {
00119             setDefault(keys[i],  node->default_value);
00120             setProperty(keys[i], node->value);
00121           }
00122       }
00123     
00124     return *this;
00125   }
00126   
00134   Properties::~Properties(void)
00135   {  
00136     // Delete children
00137     clear();
00138     
00139     // delete myself from parent
00140     if (root != NULL)
00141       {
00142         root->removeNode(name.c_str());
00143       }
00144   };
00145   
00146   //============================================================
00147   // public fnctions
00148   //============================================================
00156   const std::string& Properties::getProperty(const std::string& key) const
00157   {
00158     std::vector<std::string> keys;
00159     split(key, '.', keys);
00160     Properties* node(NULL);
00161     if ((node = _getNode(keys, 0, this)) != NULL)
00162       {
00163         return (!node->value.empty()) ? node->value : node->default_value;
00164       }
00165     return m_empty;
00166   }
00167   
00175   const std::string& Properties::getProperty(const std::string& key,
00176                                              const std::string& def) const
00177   {
00178     const std::string& value((*this)[key]);
00179     
00180     return value.empty() ? def : value;
00181   }
00182   
00190   const std::string& Properties::operator[](const std::string& key) const
00191   {
00192     return getProperty(key);
00193   }
00194   
00202   std::string& Properties::operator[](const std::string& key)
00203   {
00204     setProperty(key, getProperty(key));
00205     Properties& prop(getNode(key));
00206     
00207     return prop.value;
00208   }
00209   
00217   const std::string& Properties::getDefault(const std::string& key) const
00218   {
00219     std::vector<std::string> keys;
00220     split(key, '.', keys);
00221     Properties* node(NULL);
00222     if ((node = _getNode(keys, 0, this)) != NULL)
00223       {
00224         return node->default_value;
00225       }
00226     return m_empty;
00227   }
00228   
00236   std::string Properties::setProperty(const std::string& key,
00237                                       const std::string& value)
00238   {
00239     std::vector<std::string> keys;
00240     split(key, '.', keys);
00241     
00242     Properties* curr(this);
00243     for (size_t i(0), len(keys.size()); i < len; ++i)
00244       {
00245         Properties* next(curr->hasKey(keys[i].c_str()));
00246         if (next == NULL)
00247           {
00248             next = new Properties(keys[i].c_str());
00249             next->root = curr;
00250             curr->leaf.push_back(next);
00251           }
00252         curr = next;
00253       }
00254     std::string retval(curr->value);
00255     curr->value = value;
00256     return retval;
00257   }
00258   
00266   std::string Properties::setDefault(const std::string& key,
00267                                      const std::string& value)
00268   {
00269     std::vector<std::string> keys;
00270     split(key, '.', keys);
00271     
00272     Properties* curr(this);
00273     for (size_t i(0), len(keys.size()); i < len; ++i)
00274       {
00275         Properties* next(curr->hasKey(keys[i].c_str()));
00276         if (next == NULL)
00277           {
00278             next = new Properties(keys[i].c_str());
00279             next->root = curr;
00280             curr->leaf.push_back(next);
00281           }
00282         curr = next;
00283       }
00284     curr->default_value = value;
00285     return value;
00286   }
00287   
00295   void Properties::setDefaults(const char* defaults[], long num)
00296   {
00297     for (long i = 0; i < num && defaults[i][0] != '\0' ; i += 2)
00298       {
00299         std::string key(defaults[i]);
00300         std::string value(defaults[i + 1]);
00301         
00302         coil::eraseHeadBlank(key);
00303         coil::eraseTailBlank(key);
00304         
00305         coil::eraseHeadBlank(value);
00306         coil::eraseTailBlank(value);
00307         
00308         setDefault(key.c_str(), value.c_str());
00309       }
00310   }
00311   
00312   //============================================================
00313   // load and save functions
00314   //============================================================
00322   void Properties::list(std::ostream& out)
00323   {
00324     _store(out, "", this);
00325   }
00326   
00334   void Properties::load(std::istream& inStream)
00335   {
00336     std::string pline;
00337     
00338     while(!inStream.eof())
00339       {
00340         std::string tmp;
00341         coil::getlinePortable(inStream, tmp);
00342         coil::eraseHeadBlank(tmp);
00343         
00344         // Skip comments or empty lines
00345         if (tmp[0] == '#' || tmp[0] == '!' || tmp == "") continue;
00346         
00347         // line-end '\' continues entry
00348         if (tmp[tmp.size() - 1] == '\\' && !coil::isEscaped(tmp, tmp.size() - 1))
00349           {
00350             tmp.erase(tmp.size() - 1);
00351             pline += tmp;
00352             continue;
00353           }
00354         pline += tmp;
00355         
00356         // Skip empty line (made of only ' ' or '\t')
00357         if (pline == "") continue;
00358         
00359         std::string key, value;
00360         splitKeyValue(pline, key, value);
00361         key = coil::unescape(key);
00362         coil::eraseHeadBlank(key);
00363         coil::eraseTailBlank(key);
00364         
00365         value = coil::unescape(value);
00366         coil::eraseHeadBlank(value);
00367         coil::eraseTailBlank(value);
00368         
00369         setProperty(key.c_str(), value.c_str());
00370         pline.clear();
00371       }
00372   }
00373   
00381   void Properties::save(std::ostream& out, const std::string& header)
00382   {
00383     store(out, header);
00384     return;
00385   }
00386   
00394   void Properties::store(std::ostream& out, const std::string& header)
00395   {
00396     out << "# " << header << std::endl;
00397     _store(out, "", this);
00398   }
00399   
00400   //============================================================
00401   // other util functions
00402   //============================================================
00410   std::vector<std::string> Properties::propertyNames() const
00411   {
00412     std::vector<std::string> names;
00413     for (size_t i(0), len(leaf.size()); i < len; ++i)
00414       {
00415         _propertiyNames(names, leaf[i]->name, leaf[i]);
00416       }
00417     return names;
00418   }
00419   
00427   int Properties::size(void) const
00428   {
00429     return static_cast<int>(propertyNames().size());
00430   }
00431   
00439   Properties* const Properties::findNode(const std::string& key) const
00440   {
00441     if (key.empty()) { return 0; }
00442     std::vector<std::string> keys;
00443     //    std::string value;
00444     split(key, '.', keys);
00445     return _getNode(keys, 0, this);
00446   }
00447   
00455   Properties& Properties::getNode(const std::string& key)
00456   {
00457     if (key.empty()) { return *this; }
00458     Properties* const leaf(findNode(key));
00459     if (leaf != 0)
00460       {
00461         return *leaf;
00462       }
00463     this->createNode(key);
00464     return *findNode(key);
00465   }
00466 
00474   bool Properties::createNode(const std::string& key)
00475   {
00476     if (key.empty()) { return false; }
00477     
00478     if (findNode(key) != 0) 
00479       {
00480         return false;
00481       }
00482     (*this)[key] = "";
00483     return true;
00484   }
00485 
00493   Properties* Properties::removeNode(const char* leaf_name)
00494   {
00495     std::vector<Properties*>::iterator it(leaf.begin()), it_end(leaf.end());
00496     Properties* prop;
00497     while (it != it_end)
00498       {
00499         if ((*it)->name == leaf_name)
00500           {
00501             prop = *it;
00502             leaf.erase(it);
00503             return prop;
00504           }
00505         ++it;
00506       }
00507     return NULL;
00508   }
00509   
00517   Properties* Properties::hasKey(const char* key) const
00518   {
00519     for (size_t i(0), len(leaf.size()); i < len; ++i)
00520       {
00521         if (leaf[i]->name == key)
00522           return leaf[i];
00523       }
00524     return NULL;
00525   }
00526   
00534   void Properties::clear(void)
00535   {
00536     while (!leaf.empty())
00537       {
00538         if (leaf.back() != NULL) // recursive delete
00539           delete leaf.back();    // back() returns always new
00540       }
00541   }
00542   
00550   Properties& Properties::operator<<(const Properties& prop)
00551   {
00552     std::vector<std::string> keys;
00553     keys = prop.propertyNames();
00554     for (size_t i(0), len(prop.size()); i < len; ++i)
00555       {
00556         (*this)[keys[i]] = prop[keys[i]];
00557       }
00558     return (*this);
00559   }
00560   
00561   //------------------------------------------------------------
00562   // Protected functions
00563   //------------------------------------------------------------
00571   void Properties::splitKeyValue(const std::string& str, std::string& key,
00572                                  std::string& value)
00573   {
00574     std::string::size_type i(0);
00575     std::string::size_type len(str.size());
00576     
00577     while (i < len)
00578       {
00579         if ((str[i] == ':' || str[i] == '=') && !coil::isEscaped(str, i))
00580           {
00581             key   = str.substr(0, i); // substr(0, i) returns 0...(i-1) chars.
00582             coil::eraseHeadBlank(key);
00583             coil::eraseTailBlank(key);
00584             value = str.substr(i + 1);
00585             coil::eraseHeadBlank(value);
00586             coil::eraseTailBlank(value);
00587             return;
00588           }
00589         ++i;
00590       }
00591     
00592     // If no ':' or '=' exist, ' ' would be delimiter.
00593     i = 0;
00594     while (i < len)
00595       {
00596         if ((str[i] == ' ') && !coil::isEscaped(str, i))
00597           {
00598             key   = str.substr(0, i); // substr(0, i) returns 0...(i-1) chars.
00599             coil::eraseHeadBlank(key);
00600             coil::eraseTailBlank(key);
00601             value = str.substr(i + 1);
00602             coil::eraseHeadBlank(value);
00603             coil::eraseTailBlank(value);
00604             return;
00605           }
00606         ++i;
00607       }
00608     
00609     key = str;
00610     value = "";
00611     return;
00612   }
00613   
00621   bool Properties::split(const std::string& str, const char delim,
00622                          std::vector<std::string>& value)
00623   {
00624     if (str.empty()) return false;
00625     
00626     std::string::size_type begin_it(0), end_it(0);
00627     std::string::size_type len(str.size());
00628     
00629     while (end_it < len)
00630       {
00631         if ((str[end_it] == delim) && !coil::isEscaped(str, end_it))
00632           {
00633             // substr(0, i) returns 0...(i-1) chars.
00634             value.push_back(str.substr(begin_it, end_it - begin_it));
00635             begin_it = end_it + 1;
00636           }
00637         ++end_it;
00638       }
00639     value.push_back(str.substr(begin_it, end_it));
00640     return true;
00641   }
00642   
00650   Properties*
00651   Properties::_getNode(std::vector<std::string>& keys,
00652                        std::vector<Properties*>::size_type index,
00653                        const Properties* curr)
00654   {
00655     Properties* next(curr->hasKey(keys[index].c_str()));
00656     
00657     if (next == NULL)
00658       {
00659         return NULL;
00660       }
00661     
00662     if (index < keys.size() - 1) // node
00663       {
00664         return next->_getNode(keys, ++index, next);
00665       }
00666     else
00667       {
00668         return next;
00669       }
00670     return NULL;
00671   }
00672   
00680   void
00681   Properties::_propertiyNames(std::vector<std::string>& names,
00682                               std::string curr_name,
00683                               const Properties* curr)
00684   {
00685     if (!curr->leaf.empty())
00686       {
00687         for (size_t i(0), len(curr->leaf.size()); i < len; ++i)
00688           {
00689             std::string next_name;
00690             //      if (curr_name == "") next_name = curr->leaf[i]->name;
00691             next_name = curr_name + "." + curr->leaf[i]->name;
00692             _propertiyNames(names, next_name, curr->leaf[i]);
00693           }
00694       }
00695     else
00696       {
00697         names.push_back(curr_name);
00698       }
00699     return;
00700   }
00701   
00709   void
00710   Properties::_store(std::ostream& out, std::string curr_name,
00711                      Properties* curr)
00712   {
00713     if (!curr->leaf.empty())
00714       {
00715         
00716         for (size_t i(0), len(curr->leaf.size()); i < len; ++i)
00717           {
00718             std::string next_name;
00719             if (curr_name == "")
00720               {
00721                 next_name = curr->leaf[i]->name;
00722               }
00723             else
00724               {
00725                 next_name = curr_name + "." + curr->leaf[i]->name;
00726               }
00727             _store(out, next_name, curr->leaf[i]);
00728           }
00729       }
00730     
00731     if (curr->root != NULL)
00732       {
00733         if (curr->value.length() > 0)
00734           {
00735             out << curr_name << ": " << coil::escape(curr->value) << std::endl;
00736           }
00737       }
00738   }
00739   
00747   std::ostream&
00748   Properties::_dump(std::ostream& out, const Properties& curr, int index)
00749   {
00750     if (index != 0) out << indent(index) << "- " << curr.name;
00751     if (curr.leaf.empty())
00752       {
00753         if (curr.value.empty())
00754           {
00755             out << ": " << curr.default_value << std::endl;
00756           }
00757         else
00758           {
00759             out << ": " << curr.value << std::endl;
00760           }
00761         return out;
00762       }
00763     if (index != 0) out << std::endl;
00764     for (size_t i(0), len(curr.leaf.size()); i < len ;++i)
00765       {
00766         _dump(out, *(curr.leaf[i]), index + 1);
00767       }
00768     return out;
00769   }
00770   
00778   std::string Properties::indent(int index)
00779   {
00780     std::string space;
00781     for (int i(0); i < index - 1; ++i)
00782       {
00783         space += "  ";
00784       }
00785     return space;
00786   }
00787   
00795   std::string indent(int index)
00796   {
00797     std::string space;
00798     for (int i(0); i < index - 1; ++i)
00799       {
00800         space += "  ";
00801       }
00802     return space;
00803   }
00804   
00812   std::ostream& operator<<(std::ostream& lhs, const Properties& rhs)
00813   {
00814     return rhs._dump(lhs, rhs, 0);
00815   }
00816 }; // namespace coil


openrtm_aist
Author(s): Noriaki Ando
autogenerated on Thu Aug 27 2015 14:16:38