/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ #include "plConfigInfo.h" #include "hsTypes.h" #include "hsStlUtils.h" #include #include #include #include const std::string& plConfigInfo::GlobalSection() { static std::string section("global"); return section; } plConfigInfo::plConfigInfo() { } plConfigInfo::plConfigInfo(const plConfigInfo & src) : fSections(src.fSections) { } plConfigInfo & plConfigInfo::operator =(const plConfigInfo & src) { fSections = src.fSections; return *this; } void plConfigInfo::Clear() { fSections.clear(); } void plConfigInfo::RemoveSection(const std::string & section) { fSections.erase(section.c_str()); } void plConfigInfo::RemoveKey(const std::string & section, const std::string & key) { Sections::iterator si = fSections.find(section.c_str()); if (si != fSections.end()) fSections[section.c_str()].RemoveKey(key); } bool plConfigInfo::HasSection(const std::string & section) const { return fSections.find(section.c_str())!=fSections.end(); } bool plConfigInfo::HasKey(const std::string & section, const std::string & key) { Sections::iterator si = fSections.find(section.c_str()); if (si == fSections.end()) return false; return (si->second.HasKey(key)); } bool plConfigInfo::HasKeyAny(const std::string & key) { for (Sections::iterator si=fSections.begin(); si!=fSections.end(); ++si) { if (si->second.HasKey(key)) return true; } return false; } bool plConfigInfo::HasKeyIn(const std::string & key, const char * section1, ...) { const char * section = section1; va_list va; va_start(va,section1); std::vector sections; while (section) { sections.push_back( section ); section = va_arg(va,const char *); } va_end(va); return HasKeyIn( key, sections ); } bool plConfigInfo::HasKeyIn(const std::string & key, const std::vector & sections ) { for ( int i=0; isecond.KeyHasValue(key,value); } bool plConfigInfo::KeyHasValue(const std::string & section, const std::string & key, int value) { Sections::iterator si = fSections.find(section.c_str()); if (si == fSections.end()) return false; return si->second.KeyHasValue(key,value); } bool plConfigInfo::KeyHasValue(const std::string & section, const std::string & key, double value) { Sections::iterator si = fSections.find(section.c_str()); if (si == fSections.end()) return false; return si->second.KeyHasValue(key,value); } bool plConfigInfo::AddValue(const std::string & section, const std::string & key, const std::string & value, KAddValueMode mode) { fSections[section.c_str()].AddValue(key,value,mode); return true; } bool plConfigInfo::AddValue(const std::string & section, const std::string & key, int value, KAddValueMode mode) { char buf[20]; sprintf(buf, "%d", value); std::string v(buf); return AddValue(section,key,v,mode); } bool plConfigInfo::AddValue(const std::string & section, const std::string & key, double value, KAddValueMode mode) { char buf[30]; sprintf(buf, "%f", value); std::string v(buf); return AddValue(section,key,v,mode); } bool plConfigInfo::AddValues(const std::string & section, const std::string & key, const std::vector & values, KAddValueMode mode) { return fSections[section.c_str()].AddValues(key,values); } plKeysAndValues plConfigInfo::GetSection(const std::string & section, bool & found) { found = HasSection(section); if (found) return fSections[section.c_str()]; else return plKeysAndValues(); // empty } std::vector plConfigInfo::GetSectionNames() { std::vector results; for (Sections::const_iterator ii=fSections.begin(); ii!=fSections.end(); ++ii) results.push_back(ii->first.c_str()); return results; } std::string plConfigInfo::GetValue(const std::string & section, const std::string & key, const std::string & defval, bool * outFound) const { return fSections[section.c_str()].GetValue(key,defval,outFound); } int plConfigInfo::GetValue(const std::string & section, const std::string & key, int defval, bool * outFound) const { return fSections[section.c_str()].GetValue(key,defval,outFound); } double plConfigInfo::GetValue(const std::string & section, const std::string & key, double defval, bool * outFound) const { return fSections[section.c_str()].GetValue(key,defval,outFound); } std::vector plConfigInfo::GetAllValues(const std::string & section, const std::string & key) const { Sections::iterator si = fSections.find(section.c_str()); if (si != fSections.end()) return si->second.GetAllValues(key); std::vector empty; return empty; } std::string plConfigInfo::GetValueAny(const std::string & key, const std::string & defval, bool * outFound) const { if (outFound) *outFound=false; for (Sections::iterator si=fSections.begin(); si!=fSections.end(); ++si) if (si->second.HasKey(key)) return si->second.GetValue(key,defval,outFound); return defval; } int plConfigInfo::GetValueAny(const std::string & key, int defval, bool * outFound) const { if (outFound) *outFound=false; for (Sections::iterator si=fSections.begin(); si!=fSections.end(); ++si) if (si->second.HasKey(key)) return si->second.GetValue(key,defval,outFound); return defval; } double plConfigInfo::GetValueAny(const std::string & key, double defval, bool * outFound) const { if (outFound) *outFound=false; for (Sections::iterator si=fSections.begin(); si!=fSections.end(); ++si) if (si->second.HasKey(key)) return si->second.GetValue(key,defval,outFound); return defval; } std::vector plConfigInfo::GetAllValuesAny(const std::string & key) const { for (Sections::iterator si=fSections.begin(); si!=fSections.end(); ++si) if (si->second.HasKey(key)) return si->second.GetAllValues(key); std::vector empty; return empty; } std::string plConfigInfo::GetValueIn(const std::string & key, const std::string & defval, bool * outFound, const char * section1, ...) const { if (outFound) *outFound=false; const char * section = section1; va_list sections; va_start(sections,section1); while (section) { if (HasSection(section)) { plKeysAndValues & kv = fSections[section]; if (kv.HasKey(key)) return kv.GetValue(key,defval,outFound); } section = va_arg(sections,const char *); } va_end(sections); return defval; } std::string plConfigInfo::GetValueIn(const std::string & key, const std::string & defval, bool * outFound, const std::vector & sections ) const { if (outFound) *outFound=false; for ( int i=0; i & sections ) const { if (outFound) *outFound=false; for ( int i=0; i & sections ) const { if (outFound) *outFound=false; for ( int i=0; i plConfigInfo::GetAllValuesIn(const std::string & key, const char * section1, ...) { const char * section = section1; va_list sections; va_start(sections,section1); std::vector result; while (section) { if (HasSection(section)) { plKeysAndValues & kv = fSections[section]; if (kv.HasKey(key)) { std::vector values = kv.GetAllValues(key); result.insert(result.end(),values.begin(),values.end()); } } section = va_arg(sections,const char *); } va_end(sections); return result; } bool plConfigInfo::GetSectionIterators(Sections::const_iterator & iter, Sections::const_iterator & end) const { iter = fSections.begin(); end = fSections.end(); return true; } bool plConfigInfo::GetKeyIterators(const xtl::istring & section, Keys::const_iterator & iter, Keys::const_iterator & end) const { Sections::const_iterator si = fSections.find(section); if (si==fSections.end()) return false; return fSections[section].GetKeyIterators(iter, end); } bool plConfigInfo::GetValueIterators(const xtl::istring & section, const xtl::istring & key, Values::const_iterator & iter, Values::const_iterator & end) const { Sections::const_iterator si = fSections.find(section); if (si==fSections.end()) return false; return fSections[section].GetValueIterators(key, iter, end); } bool plConfigInfo::ReadFrom(plConfigSource * src, KAddValueMode mode) { return src->ReadInto(*this,mode); } bool plConfigInfo::WriteTo(plConfigSource * src) { return src->WriteOutOf(*this); } //////////////////////////////////////////////// void plConfigSource::SplitAt(std::string & key, std::string & value, char splitter, std::string & in) { if(in.length() == 0) return; int t = in.find(splitter); if(t == std::string::npos) { key = in; return; } key.assign(in.substr(0,t)); value.assign(in.substr(t+1,in.size()-t-1)); } bool plConfigSource::ReadString(const std::string & in) { std::string work = in; xtl::trim(work); // comment if (work[0] == '#') return true; // comment if (work[0] == ';') return true; // section if (work[0] == '[') { int close = work.find_first_of("]"); if(close == std::string::npos) return false; fCurrSection = work.substr(1,close-1); fEffectiveSection = fCurrSection; return true; } // key=value std::string key, value; SplitAt(key, value, '=', work); // dot notation makes section change for this key=value only. int t = key.find('.'); if (t>0 && tAddValue(fEffectiveSection, key, value, fAddMode); } bool plConfigSource::ReadList(char ** l) { while(*l != NULL) { ReadString(*l); l++; } return true; } bool plConfigSource::ReadInto(plConfigInfo & configInfo, KAddValueMode mode) { fConfigInfo = &configInfo; fAddMode = mode; return true; } bool plConfigSource::WriteOutOf(plConfigInfo & configInfo) { fConfigInfo = &configInfo; return true; } ///////////////////////////////////////////////// plCmdLineConfigSource::plCmdLineConfigSource(int argc, char ** argv, const char * mySection) : fArgc(argc) , fArgv(argv) , fMySection(mySection?mySection:"") {} bool plCmdLineConfigSource::ReadInto(plConfigInfo & configInfo, KAddValueMode mode) { int argc = fArgc; char ** argv = fArgv; if (!plConfigSource::ReadInto(configInfo, mode)) return false; fCurrSection = fMySection; fEffectiveSection = fCurrSection; if(argc < 1) return true; fConfigInfo->AddValue(fEffectiveSection.c_str(), "ARGV0", *argv, fAddMode); argc--; argv++; while(argc > 0) { if(ReadString(*argv) != true) { // TODO: log error here return false; } argv++; argc--; } return true; } ///////////////////////////////////////////////// plEnvConfigSource::plEnvConfigSource(char ** envp, const char * mySection) : fEnvp(envp) , fMySection(mySection?mySection:"") {} bool plEnvConfigSource::ReadInto(plConfigInfo & configInfo, KAddValueMode mode) { if (!plConfigSource::ReadInto(configInfo, mode)) return false; if (fEnvp != NULL) { fCurrSection = fMySection; fEffectiveSection = fCurrSection; return ReadList(fEnvp); } return true; } ///////////////////////////////////////////////// plIniConfigSource::plIniConfigSource(const char * iniFileName) : fFileName(iniFileName) {} bool plIniConfigSource::ReadInto(plConfigInfo & configInfo, KAddValueMode mode) { if (!plConfigSource::ReadInto(configInfo, mode)) return false; fCurrSection = plConfigInfo::GlobalSection(); fEffectiveSection = fCurrSection; if(fFileName.size() < 2) return false; std::ifstream file; file.open(fFileName.c_str()); if(!file.is_open()) { // TODO log error here return false; } char buf[4096]; while (!file.eof()) { file.getline(buf, 4096); if(!ReadString(buf)) { // TODO log warning here } } file.close(); return true; } bool plIniConfigSource::WriteOutOf(plConfigInfo & configInfo) { if (!plConfigSource::WriteOutOf(configInfo)) return false; std::ofstream file; file.open(fFileName.c_str()); if(!file.is_open()) { // TODO log error here return false; } file << "# This is an auto-generated file." << std::endl << std::endl ; plConfigInfo::Sections::const_iterator si, se; plConfigInfo::Keys::const_iterator ki, ke; plConfigInfo::Values::const_iterator vi, ve; fConfigInfo->GetSectionIterators(si,se); for (si; si!=se; ++si) { file << std::endl << "[" << si->first.c_str() << "]"<< std::endl; if (fConfigInfo->GetKeyIterators(si->first, ki, ke)) for (ki; ki!=ke; ++ki) { if (fConfigInfo->GetValueIterators(si->first, ki->first, vi, ve)) for (vi; vi!=ve; ++vi) { file << ki->first.c_str() << "=" << vi->c_str() << std::endl; } } } file.close(); return true; } ///////////////////////////////////////////////// plIniStreamConfigSource::plIniStreamConfigSource(hsStream * stream) : fStream(stream) {} bool plIniStreamConfigSource::ReadInto(plConfigInfo & configInfo, KAddValueMode mode) { if (!plConfigSource::ReadInto(configInfo, mode)) return false; fCurrSection = "global"; fEffectiveSection = fCurrSection; if ( !fStream ) return false; char buf[4096]; while (!fStream->AtEnd()) { fStream->ReadLn( buf, sizeof(buf) ); if(!ReadString(buf)) { // TODO log warning here } } return true; } bool plIniStreamConfigSource::WriteOutOf(plConfigInfo & configInfo) { if (!plConfigSource::WriteOutOf(configInfo)) return false; if ( !fStream ) return false; std::stringstream ss; plConfigInfo::Sections::const_iterator si, se; plConfigInfo::Keys::const_iterator ki, ke; plConfigInfo::Values::const_iterator vi, ve; fConfigInfo->GetSectionIterators(si,se); for (si; si!=se; ++si) { ss << std::endl << "[" << si->first.c_str() << "]"<< std::endl; if (fConfigInfo->GetKeyIterators(si->first, ki, ke)) for (ki; ki!=ke; ++ki) { if (fConfigInfo->GetValueIterators(si->first, ki->first, vi, ve)) for (vi; vi!=ve; ++vi) { ss << ki->first.c_str() << "=" << vi->c_str() << std::endl; } } } fStream->WriteString( ss.str().c_str() ); return true; } ///////////////////////////////////////////////// plIniSectionConfigSource::plIniSectionConfigSource(const char * iniFileName, std::vector & sections) : plIniConfigSource(iniFileName) { for (int i=0; i::iterator ii = std::find(fSections.begin(), fSections.end(), fCurrSection.c_str()); if (ii==fSections.end()) return true; xtl::trim(key); xtl::trim(value); xtl::trim(value,"\"'"); if (key.size() == 0) return true; if (key == "section") fSections.push_back(value.c_str()); return fConfigInfo->AddValue(fEffectiveSection, key, value, fAddMode); } bool plIniSectionConfigSource::ReadSubSource( const char * name ) { std::vector sections; for ( int i=0; iReadFrom(&plIniSectionConfigSource( name, sections )); } ///////////////////////////////////////////////// plIniNoSectionsConfigSource::plIniNoSectionsConfigSource(const char * filename) : fFileName(filename) { fEffectiveSection = fCurrSection = ""; } bool plIniNoSectionsConfigSource::ReadString(const std::string & in) { std::string work = in; xtl::trim(work); // ignore comments if (work[0]=='#' || work[0]==';') return true; // ignore sections if (work[0] == '[') return true; // parse key value std::string key, value; SplitAt(key, value, '=', work); return ReadPair(key, value); } bool plIniNoSectionsConfigSource::ReadInto(plConfigInfo & configInfo, KAddValueMode mode) { if (!plConfigSource::ReadInto(configInfo, mode)) return false; if(fFileName.size() < 2) return false; std::ifstream file; file.open(fFileName.c_str()); if(!file.is_open()) { // TODO log error here return false; } char buf[4096]; while (!file.eof()) { file.getline(buf, 4096); if(!ReadString(buf)) { // TODO log warning here } } file.close(); return true; } bool plIniNoSectionsConfigSource::WriteOutOf(plConfigInfo & configInfo) { if (!plConfigSource::WriteOutOf(configInfo)) return false; std::ofstream file; file.open(fFileName.c_str()); if(!file.is_open()) { // TODO log error here return false; } file << "# This is an auto-generated file." << std::endl << std::endl ; plConfigInfo::Sections::const_iterator si, se; plConfigInfo::Keys::const_iterator ki, ke; plConfigInfo::Values::const_iterator vi, ve; fConfigInfo->GetSectionIterators(si,se); for (si; si!=se; ++si) { if (fConfigInfo->GetKeyIterators(si->first, ki, ke)) for (ki; ki!=ke; ++ki) { if (fConfigInfo->GetValueIterators(si->first, ki->first, vi, ve)) for (vi; vi!=ve; ++vi) { file << ki->first.c_str() << "=" << vi->c_str() << std::endl; } } } file.close(); return true; } ///////////////////////////////////////////////// bool plDebugConfigSource::WriteOutOf(plConfigInfo & configInfo) { if (!plConfigSource::WriteOutOf(configInfo)) return false; plConfigInfo::Sections::const_iterator si, se; plConfigInfo::Keys::const_iterator ki, ke; plConfigInfo::Values::const_iterator vi, ve; char buf[1024]; fConfigInfo->GetSectionIterators(si,se); for (si; si!=se; ++si) { sprintf(buf,"\n[%s]\n",si->first.c_str()); hsStatusMessage(buf); if (fConfigInfo->GetKeyIterators(si->first, ki, ke)) for (ki; ki!=ke; ++ki) { if (fConfigInfo->GetValueIterators(si->first, ki->first, vi, ve)) for (vi; vi!=ve; ++vi) { sprintf(buf,"%s=%s\n",ki->first.c_str(),vi->c_str()); hsStatusMessage(buf); } } } return true; } //////////////////////////////////////////////////////////////////// void plConfigValueBase::ConfigRead(plConfigInfo * opts) { if (fReadEvaluate()) { std::string value; bool found; value = opts->GetValue(GetConfigGroup(),GetConfigName(),"",&found); if (found) SetValue(fReadModify(value).c_str()); } } void plConfigValueBase::ConfigWrite(plConfigInfo * opts) { if (fWriteEvaluate()) { opts->AddValue(GetConfigGroup(),GetConfigName(),fWriteModify(GetValue()),kAlwaysAdd); } } void plConfigValueBase::SetValue(const char * value) { ISetValue(fSetModify(value).c_str()); } std::string plConfigValueBase::GetValue() const { return fGetModify(IGetValue()); } void plConfigValueBase::SetReadEvaluate(plClass * targetObj, TEvaluate evalFunc) { fReadEvaluate = plEvaluate(targetObj,evalFunc); } void plConfigValueBase::SetWriteEvaluate(plClass * targetObj, TEvaluate evalFunc) { fWriteEvaluate = plEvaluate(targetObj,evalFunc); } void plConfigValueBase::SetWriteEvaluate(plClass * targetObj, TEvaluateConst evalFunc) { fWriteEvaluate = plEvaluate(targetObj,evalFunc); } void plConfigValueBase::SetReadModify(plClass * targetObj, TModify modifyFunc) { fReadModify = plModify(targetObj,modifyFunc); } void plConfigValueBase::SetWriteModify(plClass * targetObj, TModify modifyFunc) { fWriteModify = plModify(targetObj,modifyFunc); } void plConfigValueBase::SetGetModify(plClass * targetObj, TModify modifyFunc) { fGetModify = plModify(targetObj,modifyFunc); } void plConfigValueBase::SetSetModify(plClass * targetObj, TModify modifyFunc) { fSetModify = plModify(targetObj,modifyFunc); } //////////////////////////////////////////////////////////////////// plConfigGroup::plConfigGroup(const char * groupName) : fGroupName(groupName) {} bool plConfigGroup::Read(plConfigSource * src) { if (!fOpts.ReadFrom(src)) return false; for (int i=0; iConfigRead(&fOpts); return true; } bool plConfigGroup::Write(plConfigSource * src) { for (int i=0; iConfigWrite(&fOpts); return fOpts.WriteTo(src); } void plConfigGroup::AddItem(plConfigValueBase * item, const char * name) { item->SetConfigGroup(fGroupName.c_str()); if (name) item->SetConfigName(name); fItems.push_back(item); } //////////////////////////////////////////////////////////////////// plConfigAggregateValue::plConfigAggregateValue( const char * name, plConfigValueBase * item1, plConfigValueBase * item2, plConfigValueBase * item3, plConfigValueBase * item4, plConfigValueBase * item5, plConfigValueBase * item6, plConfigValueBase * item7) { SetConfigName(name); AddItems(item1,item2,item3,item4,item5,item6,item7); } void plConfigAggregateValue::AddItems( plConfigValueBase * item1, plConfigValueBase * item2, plConfigValueBase * item3, plConfigValueBase * item4, plConfigValueBase * item5, plConfigValueBase * item6, plConfigValueBase * item7) { fItems.clear(); if (item1) AddItem(item1); if (item2) AddItem(item2); if (item3) AddItem(item3); if (item4) AddItem(item4); if (item5) AddItem(item5); if (item6) AddItem(item6); if (item7) AddItem(item7); } void plConfigAggregateValue::ISetValue(const char * value) { std::string work = value; int p=0,i=0; do { xtl::trim(work); p = work.find(" "); fItems[i]->SetValue(work.substr(0,p).c_str()); work.erase(0,p); i++; } while (iGetValue()); value.append(" "); } return xtl::trim(value); } void plConfigAggregateValue::AddItem(plConfigValueBase * item) { fItems.push_back(item); } //////////////////////////////////////////////////////////////////// plWWWAuthenticateConfigSource::plWWWAuthenticateConfigSource(const std::string& auth) : fAuth(auth) { fEffectiveSection = fCurrSection = ""; } bool plWWWAuthenticateConfigSource::ReadInto(plConfigInfo & configInfo, KAddValueMode mode) { if (!plConfigSource::ReadInto(configInfo, mode)) return false; fCurrSection = "global"; fEffectiveSection = fCurrSection; unsigned int i = 0; while (i < fAuth.size()) { bool inQuote = false; unsigned int begin = i,end; while (i < fAuth.size() && ((fAuth[i] != ',' && !inQuote) || inQuote)) { if (fAuth[i] == '"') inQuote = ! inQuote; i++; } end = i; std::string buf; buf.assign(fAuth,begin,end-begin); if(!ReadString(buf.c_str())) { // TODO log warning here } i++; } return true; }