/** * Tencent is pleased to support the open source community by making Tars available. * * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ #include #include #include "util/tc_config.h" #include "util/tc_common.h" namespace tars { TC_ConfigDomain::TC_ConfigDomain(const string &sLine) { _name = TC_Common::trim(sLine); } TC_ConfigDomain::~TC_ConfigDomain() { destroy(); } TC_ConfigDomain::TC_ConfigDomain(const TC_ConfigDomain &tcd) { (*this) = tcd; } TC_ConfigDomain& TC_ConfigDomain::operator=(const TC_ConfigDomain &tcd) { if(this != &tcd) { destroy(); _name = tcd._name; _param = tcd._param; _key = tcd._key; _domain= tcd._domain; _line = tcd._line; const map & m = tcd.getDomainMap(); map::const_iterator it = m.begin(); while(it != m.end()) { _subdomain[it->first] = it->second->clone(); ++it; } } return *this; } TC_ConfigDomain::DomainPath TC_ConfigDomain::parseDomainName(const string& path, bool bWithParam) { TC_ConfigDomain::DomainPath dp; if(bWithParam) { string::size_type pos1 = path.find_first_of(TC_CONFIG_PARAM_BEGIN); if(pos1 == string::npos) { throw TC_Config_Exception("[TC_Config::parseDomainName] : param path '" + path + "' is invalid!" ); } if(path[0] != TC_CONFIG_DOMAIN_SEP) { throw TC_Config_Exception("[TC_Config::parseDomainName] : param path '" + path + "' must start with '/'!" ); } string::size_type pos2 = path.find_first_of(TC_CONFIG_PARAM_END); if(pos2 == string::npos) { throw TC_Config_Exception("[TC_Config::parseDomainName] : param path '" + path + "' is invalid!" ); } dp._domains = TC_Common::sepstr(path.substr(1, pos1-1), TC_Common::tostr(TC_CONFIG_DOMAIN_SEP)); dp._param = path.substr(pos1 + 1, pos2 - pos1 - 1); } else { // if(path.length() <= 1 || path[0] != TC_CONFIG_DOMAIN_SEP) if(path[0] != TC_CONFIG_DOMAIN_SEP) { throw TC_Config_Exception("[TC_Config::parseDomainName] : param path '" + path + "' must start with '/'!" ); } dp._domains = TC_Common::sepstr(path.substr(1), TC_Common::tostr(TC_CONFIG_DOMAIN_SEP)); } return dp; } TC_ConfigDomain* TC_ConfigDomain::addSubDomain(const string& name) { if(_subdomain.find(name) == _subdomain.end()) { _domain.push_back(name); _subdomain[name] = new TC_ConfigDomain(name); } return _subdomain[name]; } string TC_ConfigDomain::getParamValue(const string &name) const { map::const_iterator it = _param.find(name); if( it == _param.end()) { throw TC_ConfigNoParam_Exception("[TC_ConfigDomain::getParamValue] param '" + name + "' not exits!"); } return it->second; } TC_ConfigDomain *TC_ConfigDomain::getSubTcConfigDomain(vector::const_iterator itBegin, vector::const_iterator itEnd) { if(itBegin == itEnd) { return this; } map::const_iterator it = _subdomain.find(*itBegin); //根据匹配规则找不到匹配的子域 if(it == _subdomain.end()) { return NULL; } //继续在子域下搜索 return it->second->getSubTcConfigDomain(itBegin + 1, itEnd); } const TC_ConfigDomain *TC_ConfigDomain::getSubTcConfigDomain(vector::const_iterator itBegin, vector::const_iterator itEnd) const { if(itBegin == itEnd) { return this; } map::const_iterator it = _subdomain.find(*itBegin); //根据匹配规则找不到匹配的子域 if(it == _subdomain.end()) { return NULL; } //继续在子域下搜索 return it->second->getSubTcConfigDomain(itBegin + 1, itEnd); } void TC_ConfigDomain::insertParamValue(const map &m) { for(auto e : m) { _param[e.first] = e.second; } map::const_iterator it = m.begin(); while(it != m.end()) { size_t i = 0; for(; i < _key.size(); i++) { if(_key[i] == it->first) { break; } } //没有该key, 则添加到最后 if(i == _key.size()) { _key.push_back(it->first); } ++it; } } void TC_ConfigDomain::setParamValue(const string &name, const string &value) { _param[name] = value; //如果key已经存在,则删除 for(vector::iterator it = _key.begin(); it != _key.end(); ++it) { if(*it == name) { _key.erase(it); break; } } _key.push_back(name); } void TC_ConfigDomain::setParamValue(const string &line) { if(line.empty()) { return; } _line.push_back(line); string::size_type pos = 0; for(; pos <= line.length() - 1; pos++) { if (line[pos] == '=') { if(pos > 0 && line[pos-1] == '\\') { continue; } string name = parse(TC_Common::trim(line.substr(0, pos), " \r\n\t")); string value; if(pos < line.length() - 1) { value = parse(TC_Common::trim(line.substr(pos + 1), " \r\n\t")); } setParamValue(name, value); return; } } // also need parse string name = parse(TC_Common::trim(line, " \r\n\t")); setParamValue(name, ""); } string TC_ConfigDomain::parse(const string& s) { if(s.empty()) { return ""; } string param; string::size_type pos = 0; for(; pos <= s.length() - 1; pos++) { char c; if(s[pos] == '\\' && pos < s.length() - 1) { switch (s[pos+1]) { case '\\': c = '\\'; pos++; break; case 'r': c = '\r'; pos++; break; case 'n': c = '\n'; pos++; break; case 't': c = '\t'; pos++; break; case '=': c = '='; pos++; break; default: throw TC_Config_Exception("[TC_ConfigDomain::parse] '" + s + "' is invalid, '" + TC_Common::tostr(s[pos]) + TC_Common::tostr(s[pos+1]) + "' couldn't be parse!" ); } param += c; } else if (s[pos] == '\\') { throw TC_Config_Exception("[TC_ConfigDomain::parse] '" + s + "' is invalid, '" + TC_Common::tostr(s[pos]) + "' couldn't be parse!" ); } else { param += s[pos]; } } return param; } string TC_ConfigDomain::reverse_parse(const string &s) { if(s.empty()) { return ""; } string param; string::size_type pos = 0; for(; pos <= s.length() - 1; pos++) { string c; switch (s[pos]) { case '\\': param += "\\\\"; break; case '\r': param += "\\r"; break; case '\n': param += "\\n"; break; case '\t': param += "\\t"; break; case '=': param += "\\="; break; case '<': case '>': throw TC_Config_Exception("[TC_ConfigDomain::reverse_parse] '" + s + "' is invalid, couldn't be parse!" ); default: param += s[pos]; } } return param; } string TC_ConfigDomain::getName() const { return _name; } void TC_ConfigDomain::setName(const string& name) { _name = name; } vector TC_ConfigDomain::getKey() const { return _key; } vector TC_ConfigDomain::getLine() const { return _line; } vector TC_ConfigDomain::getSubDomain() const { return _domain; } void TC_ConfigDomain::destroy() { _param.clear(); _key.clear(); _line.clear(); _domain.clear(); map::iterator it = _subdomain.begin(); while(it != _subdomain.end()) { delete it->second; ++it; } _subdomain.clear(); } string TC_ConfigDomain::tostr(int i) const { string sTab; for(int k = 0; k < i; ++k) { sTab += " "; } ostringstream buf; buf << sTab << "<" << reverse_parse(_name) << ">" << endl;; for(size_t n = 0; n < _key.size(); n++) { map::const_iterator it = _param.find(_key[n]); assert(it != _param.end()); //值为空, 则不打印出= if(it->second.empty()) { buf << " " << sTab << reverse_parse(_key[n]) << endl; } else { buf << " " << sTab << reverse_parse(_key[n]) << "=" << reverse_parse(it->second) << endl; } } ++i; for(size_t n = 0; n < _domain.size(); n++) { map::const_iterator itm = _subdomain.find(_domain[n]); assert(itm != _subdomain.end()); buf << itm->second->tostr(i); } buf << sTab << "" << endl; return buf.str(); } /********************************************************************/ /* TC_Config implement */ /********************************************************************/ TC_Config::TC_Config() : _root("") { } TC_Config::TC_Config(const TC_Config &tc) : _root(tc._root) { } TC_Config& TC_Config::operator=(const TC_Config &tc) { if(this != &tc) { _root = tc._root; } return *this; } void TC_Config::parse(istream &is) { _root.destroy(); stack stkTcCnfDomain; stkTcCnfDomain.push(&_root); string line; while(getline(is, line)) { line = TC_Common::trim(line, " \r\n\t"); if(line.length() == 0) { continue; } if(line[0] == '#') { continue; } else if(line[0] == '<') { string::size_type posl = line.find_first_of('>'); if(posl == string::npos) { throw TC_Config_Exception("[TC_Config::parse]:parse error! line : " + line); } if(line[1] == '/') { string sName(line.substr(2, (posl - 2))); if(stkTcCnfDomain.size() <= 0) { throw TC_Config_Exception("[TC_Config::parse]:parse error! <" + sName + "> hasn't matched domain."); } if(stkTcCnfDomain.top()->getName() != sName) { throw TC_Config_Exception("[TC_Config::parse]:parse error! <" + stkTcCnfDomain.top()->getName() + "> hasn't match <" + sName +">."); } //弹出 stkTcCnfDomain.pop(); } else { string name(line.substr(1, posl - 1)); stkTcCnfDomain.push(stkTcCnfDomain.top()->addSubDomain(name)); } } else { stkTcCnfDomain.top()->setParamValue(line); } } if(stkTcCnfDomain.size() != 1) { throw TC_Config_Exception("[TC_Config::parse]:parse error : hasn't match"); } } void TC_Config::parseFile(const string &sFileName) { if(sFileName.length() == 0) { throw TC_Config_Exception("[TC_Config::parseFile]:file name is empty"); } ifstream ff; ff.open(sFileName.c_str()); if (!ff) { THROW_EXCEPTION_SYSCODE(TC_Config_Exception, "[TC_Config::parseFile]:fopen fail: " + sFileName); // throw TC_Config_Exception("[TC_Config::parseFile]:fopen fail: " + sFileName, TC_Exception::getSystemCode()); } parse(ff); } void TC_Config::parseString(const string& buffer) { istringstream iss; iss.str(buffer); parse(iss); } string TC_Config::operator[](const string &path) const { TC_ConfigDomain::DomainPath dp = TC_ConfigDomain::parseDomainName(path, true); const TC_ConfigDomain *pTcConfigDomain = searchTcConfigDomain(dp._domains); if(pTcConfigDomain == NULL) { throw TC_ConfigNoParam_Exception("[TC_Config::operator[]] path '" + path + "' not exits!"); } return pTcConfigDomain->getParamValue(dp._param); } string TC_Config::get(const string &sName, const string &sDefault) const { try { TC_ConfigDomain::DomainPath dp = TC_ConfigDomain::parseDomainName(sName, true); const TC_ConfigDomain *pTcConfigDomain = searchTcConfigDomain(dp._domains); if(pTcConfigDomain == NULL) { return sDefault; // throw TC_ConfigNoParam_Exception("[TC_Config::get] path '" + sName + "' not exits!"); } return pTcConfigDomain->getParamValue(dp._param); } catch ( TC_ConfigNoParam_Exception &ex ) { return sDefault; } } void TC_Config::set(const string &sName, const string &value) { TC_ConfigDomain::DomainPath dp = TC_ConfigDomain::parseDomainName(sName, true); map v; v[dp._param] = value; TC_ConfigDomain *pTcConfigDomain = searchTcConfigDomain(dp._domains); if(pTcConfigDomain == NULL) { pTcConfigDomain = &_root; for(size_t i = 0; i < dp._domains.size(); i++) { pTcConfigDomain = pTcConfigDomain->addSubDomain(dp._domains[i]); } } pTcConfigDomain->insertParamValue(v); } bool TC_Config::getDomainMap(const string &path, map &m) const { TC_ConfigDomain::DomainPath dp = TC_ConfigDomain::parseDomainName(path, false); const TC_ConfigDomain *pTcConfigDomain = searchTcConfigDomain(dp._domains); if(pTcConfigDomain == NULL) { return false; } m = pTcConfigDomain->getParamMap(); return true; } map TC_Config::getDomainMap(const string &path) const { map m; TC_ConfigDomain::DomainPath dp = TC_ConfigDomain::parseDomainName(path, false); const TC_ConfigDomain *pTcConfigDomain = searchTcConfigDomain(dp._domains); if(pTcConfigDomain != NULL) { m = pTcConfigDomain->getParamMap(); } return m; } vector TC_Config::getDomainKey(const string &path) const { vector v; TC_ConfigDomain::DomainPath dp = TC_ConfigDomain::parseDomainName(path, false); const TC_ConfigDomain *pTcConfigDomain = searchTcConfigDomain(dp._domains); if(pTcConfigDomain != NULL) { v = pTcConfigDomain->getKey(); } return v; } vector TC_Config::getDomainLine(const string &path) const { vector v; TC_ConfigDomain::DomainPath dp = TC_ConfigDomain::parseDomainName(path, false); const TC_ConfigDomain *pTcConfigDomain = searchTcConfigDomain(dp._domains); if(pTcConfigDomain != NULL) { v = pTcConfigDomain->getLine(); } return v; } bool TC_Config::hasDomainVector(const string &path) const { TC_ConfigDomain::DomainPath dp = TC_ConfigDomain::parseDomainName(path, false); //根域, 特殊处理 if(dp._domains.empty()) { return !_root.getSubDomain().empty(); } const TC_ConfigDomain *pTcConfigDomain = searchTcConfigDomain(dp._domains); if(pTcConfigDomain == NULL) { return false; } return true; } bool TC_Config::getDomainVector(const string &path, vector &vtDomains) const { TC_ConfigDomain::DomainPath dp = TC_ConfigDomain::parseDomainName(path, false); //根域, 特殊处理 if(dp._domains.empty()) { vtDomains = _root.getSubDomain(); return !vtDomains.empty(); } const TC_ConfigDomain *pTcConfigDomain = searchTcConfigDomain(dp._domains); if(pTcConfigDomain == NULL) { return false; } vtDomains = pTcConfigDomain->getSubDomain(); return true; } vector TC_Config::getDomainVector(const string &path) const { TC_ConfigDomain::DomainPath dp = TC_ConfigDomain::parseDomainName(path, false); //根域, 特殊处理 if(dp._domains.empty()) { return _root.getSubDomain(); } const TC_ConfigDomain *pTcConfigDomain = searchTcConfigDomain(dp._domains); if(pTcConfigDomain == NULL) { return vector(); } return pTcConfigDomain->getSubDomain(); } TC_ConfigDomain *TC_Config::newTcConfigDomain(const string &sName) { return new TC_ConfigDomain(sName); } TC_ConfigDomain *TC_Config::searchTcConfigDomain(const vector& domains) { return _root.getSubTcConfigDomain(domains.begin(), domains.end()); } const TC_ConfigDomain *TC_Config::searchTcConfigDomain(const vector& domains) const { return _root.getSubTcConfigDomain(domains.begin(), domains.end()); } int TC_Config::insertDomain(const string &sCurDomain, const string &sAddDomain, bool bCreate) { TC_ConfigDomain::DomainPath dp = TC_ConfigDomain::parseDomainName(sCurDomain, false); TC_ConfigDomain *pTcConfigDomain = searchTcConfigDomain(dp._domains); if(pTcConfigDomain == NULL) { if(bCreate) { pTcConfigDomain = &_root; for(size_t i = 0; i < dp._domains.size(); i++) { pTcConfigDomain = pTcConfigDomain->addSubDomain(dp._domains[i]); } } else { return -1; } } pTcConfigDomain->addSubDomain(sAddDomain); return 0; } int TC_Config::insertDomainParam(const string &sCurDomain, const map &m, bool bCreate) { TC_ConfigDomain::DomainPath dp = TC_ConfigDomain::parseDomainName(sCurDomain, false); TC_ConfigDomain *pTcConfigDomain = searchTcConfigDomain(dp._domains); if(pTcConfigDomain == NULL) { if(bCreate) { pTcConfigDomain = &_root; for(size_t i = 0; i < dp._domains.size(); i++) { pTcConfigDomain = pTcConfigDomain->addSubDomain(dp._domains[i]); } } else { return -1; } } pTcConfigDomain->insertParamValue(m); return 0; } string TC_Config::tostr() const { string buffer; map msd = _root.getDomainMap(); map::const_iterator it = msd.begin(); while (it != msd.end()) { buffer += it->second->tostr(0); ++it; } return buffer; } void TC_Config::joinConfig(const TC_Config &cf, bool bUpdate) { string buffer; if(bUpdate) { buffer = tostr() + cf.tostr(); } else { buffer = cf.tostr() + tostr(); } parseString(buffer); } }