tars源码分析之8

在做软件开发时,配置可少不了,我不建议你再写了,直接看如下的代码吧:

#include <errno.h>
#include <fstream>
#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<string, TC_ConfigDomain*> & m = tcd.getDomainMap();
        map<string, TC_ConfigDomain*>::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<string>(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<string>(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<string, string>::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<string>::const_iterator itBegin, vector<string>::const_iterator itEnd)
{
    if(itBegin == itEnd)
    {
        return this;
    }

    map<string, TC_ConfigDomain*>::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<string>::const_iterator itBegin, vector<string>::const_iterator itEnd) const
{
    if(itBegin == itEnd)
    {
        return this;
    }

    map<string, TC_ConfigDomain*>::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<string, string> &m)
{
    _param.insert(m.begin(),  m.end());

    map<string, string>::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<string>::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;
        }
    }

    setParamValue(line, "");
}

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;
            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<string> TC_ConfigDomain::getKey() const
{
    return _key;
}

vector<string> TC_ConfigDomain::getLine() const
{
    return _line;
}

vector<string> TC_ConfigDomain::getSubDomain() const
{
    return _domain;
}

void TC_ConfigDomain::destroy()
{
    _param.clear();
    _key.clear();
    _line.clear();
    _domain.clear();

    map<string, TC_ConfigDomain*>::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 += "\t";
    }

    ostringstream buf;

    buf << sTab << "<" << reverse_parse(_name) << ">" << endl;;

    for(size_t n = 0; n < _key.size(); n++)
    {
        map<string, string>::const_iterator it = _param.find(_key[n]);

        assert(it != _param.end());

        //值为空, 则不打印出=
        if(it->second.empty())
        {
            buf << "\t" << sTab << reverse_parse(_key[n]) << endl;
        }
        else
        {
            buf << "\t" << sTab << reverse_parse(_key[n]) << "=" << reverse_parse(it->second) << endl;
        }
    }

    ++i;

    for(size_t n = 0; n < _domain.size(); n++)
    {
        map<string, TC_ConfigDomain*>::const_iterator itm = _subdomain.find(_domain[n]);

        assert(itm != _subdomain.end());

        buf << itm->second->tostr(i);
    }


    buf << sTab << "</" << reverse_parse(_name) << ">" << 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<TC_ConfigDomain*> 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 TC_Config_Exception("[TC_Config::parseFile]:fopen fail: " + sFileName, errno);
    }

    parse(ff);
}

void TC_Config::parseString(const string& buffer)
{
    istringstream iss;
    iss.str(buffer);

    parse(iss);
}

string TC_Config::operator[](const string &path)
{
    TC_ConfigDomain::DomainPath dp = TC_ConfigDomain::parseDomainName(path, true);

    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)
        {
            throw TC_ConfigNoParam_Exception("[TC_Config::get] path '" + sName + "' not exits!");
        }

        return pTcConfigDomain->getParamValue(dp._param);
    }
    catch ( TC_ConfigNoParam_Exception &ex )
    {
        return sDefault;
    }
}

bool TC_Config::getDomainMap(const string &path, map<string, string> &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<string, string> TC_Config::getDomainMap(const string &path) const
{
    map<string, string> 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<string> TC_Config::getDomainKey(const string &path) const
{
    vector<string> 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<string> TC_Config::getDomainLine(const string &path) const
{
    vector<string> 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::getDomainVector(const string &path, vector<string> &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<string> 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<string>();
    }

    return pTcConfigDomain->getSubDomain();
}


TC_ConfigDomain *TC_Config::newTcConfigDomain(const string &sName)
{
    return new TC_ConfigDomain(sName);
}

TC_ConfigDomain *TC_Config::searchTcConfigDomain(const vector<string>& domains)
{
    return _root.getSubTcConfigDomain(domains.begin(), domains.end());
}

const TC_ConfigDomain *TC_Config::searchTcConfigDomain(const vector<string>& 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<string, string> &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<string, TC_ConfigDomain*> msd = _root.getDomainMap();
    map<string, TC_ConfigDomain*>::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);
}

}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值