$search
00001 /* 00002 * $Id: Configuration.cpp 275 2008-03-12 14:43:31Z phbaer $ 00003 * 00004 * Copyright 2008 Carpe Noctem, Distributed Systems Group, 00005 * University of Kassel. All right reserved. 00006 * 00007 * The code is licensed under the Carpe Noctem Userfriendly BSD-Based 00008 * License (CNUBBL). Redistribution and use in source and binary forms, 00009 * with or without modification, are permitted provided that the 00010 * conditions of the CNUBBL are met. 00011 * 00012 * You should have received a copy of the CNUBBL along with this 00013 * software. The license is also available on our website: 00014 * http://carpenoctem.das-lab.net/license.txt 00015 */ 00016 00017 #include "Configuration.h" 00018 00019 namespace castor { 00020 00021 Configuration::Configuration() : 00022 filename(), 00023 configRoot(new ConfigNode("root")) 00024 {} 00025 00026 Configuration::Configuration(std::string filename) : 00027 filename(filename), configRoot(new ConfigNode("root")) 00028 { 00029 load(filename); 00030 } 00031 00032 Configuration::Configuration(std::string filename, const std::string content) : 00033 filename(filename), configRoot(new ConfigNode("root")) 00034 { 00035 load(filename, boost::shared_ptr<std::istream>(new std::istringstream(content)), false, false); 00036 } 00037 00038 void Configuration::load(std::string filename, boost::shared_ptr<std::istream> content, bool, bool) { 00039 00040 this->filename = filename; 00041 00042 int linePos = 0; 00043 int chrPos = 0; 00044 00045 std::string line; 00046 00047 ConfigNode *currentNode = this->configRoot.get(); 00048 00049 while (content->good()) { 00050 00051 std::getline(*content, line); 00052 boost::algorithm::trim_left(line); 00053 00054 int lineLen = line.size(); 00055 00056 chrPos = 1; 00057 00058 linePos++; 00059 00060 while (chrPos < lineLen - 1) { 00061 00062 if (line.size() == 0) break; 00063 00064 switch (line[0]) { 00065 00066 case '#': 00067 { 00068 std::string comment = line.substr(1, line.size() - 1); 00069 00070 boost::trim(comment); 00071 currentNode->create(ConfigNode::Comment, comment); 00072 00073 chrPos += line.size() - 1; 00074 } 00075 continue; 00076 00077 case '<': 00078 case '[': 00079 { 00080 size_t end = line.find(']'); 00081 00082 if (end == std::string::npos) { 00083 end = line.find('>'); 00084 } 00085 00086 if ((line.size() < 2) || (end == std::string::npos)) { 00087 std::ostringstream ss; 00088 ss << "Parse error in " << filename << ", line " << linePos << " character " << chrPos << ": malformed tag!"; 00089 throw ConfigException(ss.str()); 00090 } 00091 00092 if (end - 1 == 0) { 00093 std::ostringstream ss; 00094 ss << "Parse error in " << filename << ", line " << linePos << " character " << chrPos << ": malformed tag, tag name empty!"; 00095 throw ConfigException(ss.str()); 00096 } 00097 00098 std::string name = line.substr(1, end - 1); 00099 // std::cout << "'" << line << "' '" << name << "' " << end << std::endl; 00100 00101 if ((name[0] == '/') || (name[0] == '!')) { 00102 00103 if (currentNode == NULL) { 00104 std::ostringstream ss; 00105 ss << "Parse error in " << filename << ", line " << linePos << " character " << chrPos << ": no opening tag found!"; 00106 throw ConfigException(ss.str()); 00107 } 00108 00109 if (name.compare(1, name.size() - 1, currentNode->getName()) != 0) { 00110 std::ostringstream ss; 00111 ss << "Parse error in " << filename << ", line " << linePos << " character " << chrPos << ": closing tag does not match opening tag!"; 00112 throw ConfigException(ss.str()); 00113 } 00114 00115 currentNode = currentNode->getParent(); 00116 00117 // std::cout << "<- " << name << std::endl; 00118 00119 } else { 00120 00121 ConfigNode *x = currentNode->create(name); 00122 00123 currentNode = x; 00124 } 00125 00126 if (end < line.size() - 1) { 00127 line = line.substr(end + 1, line.size() - end - 1); 00128 } 00129 00130 chrPos += (end + 1); 00131 } 00132 break; 00133 00134 default: 00135 chrPos++; 00136 00137 if ((line[0] != ' ') && (line[0] != '\t')) { 00138 00139 size_t curPos = 0; 00140 bool inString = false; 00141 00142 std::ostringstream ss; 00143 00144 while (curPos < line.size()) { 00145 00146 /* if ((!inString) && 00147 ((line[curPos] == '[') || (line[curPos] == '<'))) 00148 { 00149 curPos--; 00150 break; 00151 } 00152 */ 00153 if (line[curPos] == '"') { 00154 inString = !inString; 00155 curPos++; 00156 } 00157 00158 if (curPos < line.size()) { 00159 00160 ss << line[curPos]; 00161 curPos++; 00162 } 00163 } 00164 00165 line = (curPos >= line.size() - 1 ? "" : line.substr(curPos + 1, line.size() - curPos - 1)); 00166 00167 chrPos += (curPos - 1); 00168 00169 std::string element = ss.str(); 00170 std::string key; 00171 std::string value; 00172 00173 size_t eq = element.find('='); 00174 00175 if (eq != std::string::npos) { 00176 key = element.substr(0, eq - 1); 00177 value = element.substr(eq + 1, element.size() - eq - 1); 00178 00179 boost::algorithm::trim(key); 00180 boost::algorithm::trim(value); 00181 } 00182 00183 boost::any a(value); 00184 00185 currentNode->create(key, a); 00186 00187 } else { 00188 line = line.substr(1, line.size() - 1); 00189 } 00190 00191 break; 00192 } 00193 } 00194 } 00195 00196 00197 if (this->configRoot.get() != currentNode) { 00198 std::ostringstream ss; 00199 ss << "Parse error in " << filename << ", line " << linePos << " character " << line.size() << ": no closing tag found!"; 00200 throw ConfigException(ss.str()); 00201 } 00202 } 00203 00204 void Configuration::serialize_internal(std::ostringstream *ss, ConfigNode *node) { 00205 00206 if (node == NULL) return; 00207 00208 if (node->getType() == ConfigNode::Node) { 00209 00210 *ss << std::string(4 * node->getDepth(), ' ') << "[" << node->getName() << "]" << std::endl; 00211 00212 for (std::vector<ConfigNodePtr>::iterator itr = node->getChildren()->begin(); 00213 itr != node->getChildren()->end(); itr++) 00214 { 00215 serialize_internal(ss, (*itr).get()); 00216 } 00217 00218 *ss << std::string(4 * node->getDepth(), ' ') << "[!" << node->getName() << "]" << std::endl; 00219 00220 } else if (node -> getType() == ConfigNode::Leaf) { 00221 00222 *ss << std::string(4 * node->getDepth(), ' ') << node->getName() << " = " << boost::any_cast<std::string>(node->getValue()) << std::endl; 00223 00224 } else { // Comment 00225 00226 *ss << std::string(4 * node->getDepth(), ' ') << "# " << node->getName() << std::endl; 00227 00228 } 00229 } 00230 00231 void Configuration::store() { 00232 00233 if (this->filename.size() > 0) { 00234 store(this->filename); 00235 } 00236 } 00237 00238 void Configuration::store(std::string filename) { 00239 00240 std::ostringstream ss; 00241 std::ofstream os(filename.c_str(), std::ios_base::out); 00242 00243 serialize_internal(&ss, this->configRoot.get()); 00244 00245 os << ss.str(); 00246 } 00247 00248 std::string Configuration::serialize() { 00249 00250 std::ostringstream ss; 00251 serialize_internal(&ss, this->configRoot.get()); 00252 00253 return ss.str(); 00254 } 00255 00256 void Configuration::collect(ConfigNode *node, std::vector<std::string> *params, size_t offset, std::vector<ConfigNode *> *result) { 00257 00258 std::vector<ConfigNodePtr> *children = node->getChildren(); 00259 00260 if (offset == params->size()) { 00261 result->push_back(node); 00262 return; 00263 } 00264 00265 for (size_t i = offset; i < params->size(); i++) { 00266 00267 bool found = false; 00268 00269 for (size_t j = 0; j < children->size(); j++) { 00270 00271 if ((*children)[j]->getName().compare((*params)[i]) == 0) { 00272 collect((*children)[j].get(), params, offset + 1, result); 00273 found = true; 00274 } 00275 } 00276 00277 if (!found) return; 00278 } 00279 } 00280 00281 void Configuration::collectSections(ConfigNode *node, std::vector<std::string> *params, size_t offset, std::vector<ConfigNode *> *result) { 00282 00283 std::vector<ConfigNodePtr> *children = node->getChildren(); 00284 00285 for(unsigned int i = 0; i < children->size(); i++){ 00286 00287 printf("Children %d %s\n", i, (*children)[i]->getName().c_str()); 00288 00289 } 00290 00291 printf("offset %u\n", (unsigned int)offset); 00292 printf("params->size %u\n", (unsigned int)params->size()); 00293 00294 if (offset == params->size()) { 00295 printf("pushed %s\n", node->getName().c_str()); 00296 //result->push_back(node); 00297 for(unsigned int i = 0; i < children->size(); i++){ 00298 00299 result->push_back((*children)[i].get()); 00300 00301 } 00302 00303 return; 00304 } 00305 00306 for (size_t i = offset; i < params->size(); i++) { 00307 00308 bool found = false; 00309 00310 for (size_t j = 0; j < children->size(); j++) { 00311 00312 if ((*children)[j]->getName().compare((*params)[i]) == 0) { 00313 printf("found true mit %s\n", (*children)[j]->getName().c_str()); 00314 collectSections((*children)[j].get(), params, offset + 1, result); 00315 found = true; 00316 } 00317 } 00318 00319 if (!found) return; 00320 } 00321 } 00322 00323 00324 00325 std::string Configuration::pathNotFound(std::vector<std::string> *params) { 00326 00327 std::ostringstream os; 00328 00329 if ((params == NULL) || (params->size() == 0)) { 00330 00331 os << "Empty path not found in " << this->filename << "!" << std::endl; 00332 00333 } else { 00334 00335 os << "Path '" << (*params)[0]; 00336 00337 for (size_t i = 1; i < params->size(); i++) { 00338 os << "." << (*params)[i]; 00339 } 00340 00341 os << "' not found in " << this->filename << "!" << std::endl; 00342 } 00343 00344 return os.str(); 00345 } 00346 00347 boost::shared_ptr<std::vector<std::string> > Configuration::getSections(const char *path, ...) { 00348 00349 CONSUME_PARAMS(path); 00350 00351 std::vector<ConfigNode *> nodes; 00352 00353 for(unsigned int i = 0; i < params->size(); i++){ 00354 printf("Params %d %s\n", i, (*params)[i].c_str()); 00355 00356 } 00357 00358 collectSections(this->configRoot.get(), params.get(), 0, &nodes); 00359 00360 00361 boost::shared_ptr<std::vector<std::string> > result(new std::vector<std::string>()); 00362 00363 if (nodes.size() == 0) { 00364 throw ConfigException(pathNotFound(params.get())); 00365 } 00366 00367 00368 00369 00370 for (unsigned int i = 0; i < nodes.size(); i++) { 00371 printf("Nodes as result: %u %s\n", i, nodes[i]->getName().c_str()); 00372 00373 if (nodes[i]->getType() == ConfigNode::Node) { 00374 result->push_back(nodes[i]->getName()); 00375 } 00376 } 00377 00378 return result; 00379 } 00380 00381 boost::shared_ptr<std::vector<std::string> > Configuration::getNames(const char *path, ...) { 00382 00383 CONSUME_PARAMS(path); 00384 00385 std::vector<ConfigNode *> nodes; 00386 00387 collect(this->configRoot.get(), params.get(), 0, &nodes); 00388 00389 boost::shared_ptr<std::vector<std::string> > result(new std::vector<std::string>()); 00390 00391 if (nodes.size() == 0) { 00392 throw ConfigException(pathNotFound(params.get())); 00393 } 00394 00395 for (size_t i = 0; i < nodes.size(); i++) { 00396 if (nodes[i]->getType() == ConfigNode::Leaf) { 00397 result->push_back(nodes[i]->getName()); 00398 } 00399 } 00400 00401 return result; 00402 } 00403 00404 boost::shared_ptr<std::vector<std::string> > Configuration::tryGetSections(std::string d, const char *path, ...) { 00405 00406 CONSUME_PARAMS(path); 00407 00408 std::vector<ConfigNode *> nodes; 00409 00410 collect(this->configRoot.get(), params.get(), 0, &nodes); 00411 00412 boost::shared_ptr<std::vector<std::string> > result(new std::vector<std::string>()); 00413 00414 if (nodes.size() == 0) { 00415 00416 result->push_back(d); 00417 00418 return result; 00419 } 00420 00421 for (size_t i = 0; i < nodes.size(); i++) { 00422 if (nodes[i]->getType() == ConfigNode::Node) { 00423 result->push_back(nodes[i]->getName()); 00424 } 00425 } 00426 00427 return result; 00428 } 00429 00430 boost::shared_ptr<std::vector<std::string> > Configuration::tryGetNames(std::string d, const char *path, ...) { 00431 00432 CONSUME_PARAMS(path); 00433 00434 std::vector<ConfigNode *> nodes; 00435 00436 collect(this->configRoot.get(), params.get(), 0, &nodes); 00437 00438 boost::shared_ptr<std::vector<std::string> > result(new std::vector<std::string>()); 00439 00440 if (nodes.size() == 0) { 00441 00442 result->push_back(d); 00443 00444 return result; 00445 } 00446 00447 for (size_t i = 0; i < nodes.size(); i++) { 00448 if (nodes[i]->getType() == ConfigNode::Leaf) { 00449 result->push_back(nodes[i]->getName()); 00450 } 00451 } 00452 00453 return result; 00454 } 00455 }; 00456