00001
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
00137 clear();
00138
00139
00140 if (root != NULL)
00141 {
00142 root->removeNode(name.c_str());
00143 }
00144 };
00145
00146
00147
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
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
00345 if (tmp[0] == '#' || tmp[0] == '!' || tmp == "") continue;
00346
00347
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
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
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
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)
00539 delete leaf.back();
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
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);
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
00593 i = 0;
00594 while (i < len)
00595 {
00596 if ((str[i] == ' ') && !coil::isEscaped(str, i))
00597 {
00598 key = str.substr(0, i);
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
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)
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
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 };