This commit is contained in:
TheLuda 2008-10-14 00:29:20 +02:00
parent d767495d5b
commit 800ee76535
3322 changed files with 903437 additions and 0 deletions

View file

@ -0,0 +1,174 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ConfigEnv.h"
#include "Policies/SingletonImp.h"
INSTANTIATE_SINGLETON_1(Config);
Config::Config() : mIgnoreCase(true), mConf(NULL)
{
}
Config::~Config()
{
delete mConf;
}
bool Config::SetSource(const char *file, bool ignorecase)
{
mIgnoreCase = ignorecase;
mFilename = file;
return Reload();
}
bool Config::Reload()
{
delete mConf;
mConf = new DOTCONFDocument(mIgnoreCase ?
DOTCONFDocument::CASEINSENSETIVE :
DOTCONFDocument::CASESENSETIVE);
if (mConf->setContent(mFilename.c_str()) == -1)
{
delete mConf;
mConf = NULL;
return false;
}
return true;
}
bool Config::GetString(const char* name, std::string *value)
{
if(!mConf)
return false;
DOTCONFDocumentNode const *node = mConf->findNode(name);
if(!node || !node->getValue())
return false;
*value = node->getValue();
return true;
}
bool Config::GetString(const char* name, char const **value)
{
if(!mConf)
return false;
DOTCONFDocumentNode const *node = mConf->findNode(name);
if(!node || !node->getValue())
return false;
*value = node->getValue();
return true;
}
std::string Config::GetStringDefault(const char* name, const char* def)
{
if(!mConf)
return std::string(def);
DOTCONFDocumentNode const *node = mConf->findNode(name);
if(!node || !node->getValue())
return std::string(def);
return std::string(node->getValue());
}
bool Config::GetBool(const char* name, bool *value)
{
if(!mConf)
return false;
DOTCONFDocumentNode const *node = mConf->findNode(name);
if(!node || !node->getValue())
return false;
const char* str = node->getValue();
if(strcmp(str, "true") == 0 || strcmp(str, "TRUE") == 0 ||
strcmp(str, "yes") == 0 || strcmp(str, "YES") == 0 ||
strcmp(str, "1") == 0)
{
*value = true;
}
else
*value = false;
return true;
}
bool Config::GetBoolDefault(const char* name, const bool def)
{
bool val;
return GetBool(name, &val) ? val : def;
}
bool Config::GetInt(const char* name, int *value)
{
if(!mConf)
return false;
DOTCONFDocumentNode const *node = mConf->findNode(name);
if(!node || !node->getValue())
return false;
*value = atoi(node->getValue());
return true;
}
bool Config::GetFloat(const char* name, float *value)
{
if(!mConf)
return false;
DOTCONFDocumentNode const *node = mConf->findNode(name);
if(!node || !node->getValue())
return false;
*value = atof(node->getValue());
return true;
}
int Config::GetIntDefault(const char* name, const int def)
{
int val;
return GetInt(name, &val) ? val : def;
}
float Config::GetFloatDefault(const char* name, const float def)
{
float val;
return (GetFloat(name, &val) ? val : def);
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CONFIG_H
#define CONFIG_H
#include <Policies/Singleton.h>
#include "Platform/Define.h"
class DOTCONFDocument;
class MANGOS_DLL_SPEC Config
{
public:
Config();
~Config();
bool SetSource(const char *file, bool ignorecase = true);
bool Reload();
bool GetString(const char* name, std::string *value);
bool GetString(const char* name, char const **value);
std::string GetStringDefault(const char* name, const char* def);
bool GetBool(const char* name, bool *value);
bool GetBoolDefault(const char* name, const bool def = false);
bool GetInt(const char* name, int *value);
int GetIntDefault(const char* name, const int def);
bool GetFloat(const char* name, float *value);
float GetFloatDefault(const char* name, const float def);
std::string GetFilename() const { return mFilename; }
private:
std::string mFilename;
bool mIgnoreCase;
DOTCONFDocument *mConf;
};
#define sConfig MaNGOS::Singleton<Config>::Instance()
#endif

View file

@ -0,0 +1,28 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if !defined(CONFIGENVIRONMENT_H)
#define CONFIGENVIRONMENT_H
#include "Common.h"
#include "dotconfpp/dotconfpp.h"
#include "Config.h"
#include "Log.h"
#endif

View file

@ -0,0 +1,137 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="ConfigLibrary"
ProjectGUID="{C849D54F-32A6-4025-95BE-E64D1CF0686E}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="4"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=""
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/ConfigLibrary.lib"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="4"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/ConfigLibrary.lib"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\Config.cpp">
</File>
<File
RelativePath=".\dotconfpp\dotconfpp.cpp">
</File>
<File
RelativePath=".\dotconfpp\mempool.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath=".\Config.h">
</File>
<File
RelativePath=".\ConfigEnv.h">
</File>
<File
RelativePath=".\dotconfpp\dotconfpp.h">
</File>
<File
RelativePath=".\dotconfpp\mempool.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -0,0 +1,40 @@
# Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
#
# 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 2 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, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
## Process this file with automake to produce Makefile.in
## Sub-directories to parse
## CPP flags for includes, defines, etc.
AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(srcdir)/../../../dep/include -I$(srcdir)/../../framework -I$(srcdir)/../../shared -I$(srcdir)/../../../dep/include/g3dlite
## Build MaNGOS shared library and its parts as convenience library.
# All libraries will be convenience libraries. Might be changed to shared
# later.
noinst_LIBRARIES = libmangosconfig.a
libmangosconfig_a_SOURCES = \
dotconfpp/dotconfpp.cpp \
dotconfpp/dotconfpp.h \
dotconfpp/mempool.cpp \
dotconfpp/mempool.h \
Config.cpp \
Config.h \
ConfigEnv.h
# VC++ project workspace for dotconfpp
EXTRA_DIST = \
ConfigLibrary.vcproj

View file

@ -0,0 +1,583 @@
#include "Common.h"
#include "dotconfpp.h"
#if !defined(R_OK)
#define R_OK 04
#endif
DOTCONFDocumentNode::DOTCONFDocumentNode():previousNode(NULL), nextNode(NULL), parentNode(NULL), childNode(NULL),
values(NULL), valuesCount(0),
name(NULL), lineNum(0), fileName(NULL), closed(true)
{
}
DOTCONFDocumentNode::~DOTCONFDocumentNode()
{
free(name);
if(values != NULL){
for(int i = 0 ; i < valuesCount; i++){
free(values[i]);
}
free(values);
}
}
void DOTCONFDocumentNode::pushValue(char * _value)
{
++valuesCount;
values = (char**)realloc(values, valuesCount*sizeof(char*));
values[valuesCount-1] = strdup(_value);
}
const char* DOTCONFDocumentNode::getValue(int index) const
{
if(index >= valuesCount){
return NULL;
}
return values[index];
}
DOTCONFDocument::DOTCONFDocument(DOTCONFDocument::CaseSensitive caseSensitivity):
mempool(NULL),
curParent(NULL), curPrev(NULL), curLine(0), file(NULL), fileName(NULL)
{
if(caseSensitivity == CASESENSETIVE){
cmp_func = strcmp;
} else {
cmp_func = strcasecmp;
}
mempool = new AsyncDNSMemPool(1024);
mempool->initialize();
}
DOTCONFDocument::~DOTCONFDocument()
{
for(std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin(); i != nodeTree.end(); i++){
delete(*i);
}
for(std::list<char*>::iterator i = requiredOptions.begin(); i != requiredOptions.end(); i++){
free(*i);
}
for(std::list<char*>::iterator i = processedFiles.begin(); i != processedFiles.end(); i++){
free(*i);
}
free(fileName);
delete mempool;
}
int DOTCONFDocument::cleanupLine(char * line)
{
char * start = line;
char * bg = line;
bool multiline = false;
bool concat = false;
char * word = NULL;
if(!words.empty() && quoted)
concat = true;
while(*line){
if((*line == '#' || *line == ';') && !quoted){
*bg = 0;
if(strlen(start)){
if(concat){
word = (char*)mempool->alloc(strlen(words.back())+strlen(start)+1);
strcpy(word, words.back());
strcat(word, start);
words.pop_back();
concat = false;
} else {
word = mempool->strdup(start);
}
words.push_back(word);
}
break;
}
if(*line == '=' && !quoted){
*line = ' ';continue;
}
// Allowing \" in there causes problems with directory paths
// like "C:\MaNGOS\"
//if(*line == '\\' && (*(line+1) == '"' || *(line+1) == '\'')){
if(*line == '\\' && (*(line+1) == '\'')) {
*bg++ = *(line+1);
line+=2; continue;
}
if(*line == '\\' && *(line+1) == 'n'){
*bg++ = '\n';
line+=2; continue;
}
if(*line == '\\' && *(line+1) == 'r'){
*bg++ = '\r';
line+=2; continue;
}
if(*line == '\\' && (*(line+1) == '\n' || *(line+1) == '\r')){
*bg = 0;
if(strlen(start)){
if(concat){
word = (char*)mempool->alloc(strlen(words.back())+strlen(start)+1);
strcpy(word, words.back());
strcat(word, start);
words.pop_back();
concat = false;
} else {
word = mempool->strdup(start);
}
words.push_back(word);
}
multiline = true;
break;
}
if(*line == '"' || *line == '\''){
quoted = !quoted;
++line; continue;
}
if(isspace(*line) && !quoted){
*bg++ = 0;
if(strlen(start)){
if(concat){
word = (char*)mempool->alloc(strlen(words.back())+strlen(start)+1);
strcpy(word, words.back());
strcat(word, start);
words.pop_back();
concat = false;
} else {
word = mempool->strdup(start);
}
words.push_back(word);
}
start = bg;
while(isspace(*++line)) {}
continue;
}
*bg++ = *line++;
}
if(quoted && !multiline){
error(curLine, fileName, "unterminated quote");
return -1;
}
return multiline?1:0;
}
int DOTCONFDocument::parseLine()
{
char * word = NULL;
char * nodeName = NULL;
char * nodeValue = NULL;
DOTCONFDocumentNode * tagNode = NULL;
bool newNode = false;
for(std::list<char*>::iterator i = words.begin(); i != words.end(); i++) {
word = *i;
if(*word == '<'){
newNode = true;
}
if(newNode){
nodeValue = NULL;
nodeName = NULL;
newNode = false;
}
size_t wordLen = strlen(word);
if(word[wordLen-1] == '>'){
word[wordLen-1] = 0;
newNode = true;
}
if(nodeName == NULL){
nodeName = word;
bool closed = true;
if(*nodeName == '<'){
if(*(nodeName+1) != '/'){
++nodeName;
closed = false;
} else {
nodeName+=2;
std::list<DOTCONFDocumentNode*>::reverse_iterator itr=nodeTree.rbegin();
for(; itr!=nodeTree.rend(); ++itr){
if(!cmp_func(nodeName, (*itr)->name) && !(*itr)->closed){
(*itr)->closed = true;
curParent = (*itr)->parentNode;
curPrev = *itr;
break;
}
}
if(itr==nodeTree.rend()){
error(curLine, fileName, "not matched closing tag </%s>", nodeName);
return -1;
}
continue;
}
}
tagNode = new DOTCONFDocumentNode;
tagNode->name = strdup(nodeName);
tagNode->document = this;
tagNode->fileName = processedFiles.back();
tagNode->lineNum = curLine;
tagNode->closed = closed;
if(!nodeTree.empty()){
DOTCONFDocumentNode * prev = nodeTree.back();
if(prev->closed){
curPrev->nextNode = tagNode;
tagNode->previousNode = curPrev;
tagNode->parentNode = curParent;
} else {
prev->childNode = tagNode;
tagNode->parentNode = prev;
curParent = prev;
}
}
nodeTree.push_back(tagNode);
curPrev = tagNode;
} else {
nodeValue = word;
tagNode->pushValue(nodeValue);
}
}
return 0;
}
int DOTCONFDocument::parseFile(DOTCONFDocumentNode * _parent)
{
char str[512];
int ret = 0;
curLine = 0;
curParent = _parent;
quoted = false;
size_t slen = 0;
while(fgets(str, 511, file)){
++curLine;
slen = strlen(str);
if( slen >= 510 ){
error(curLine, fileName, "warning: line too long");
}
if(str[slen-1] != '\n'){
str[slen] = '\n';
str[slen+1] = 0;
}
if((ret = cleanupLine(str)) == -1){
break;
}
if(ret == 0){
if(!words.empty()){
ret = parseLine();
mempool->free();
words.clear();
if(ret == -1){
break;
}
}
}
}
return ret;
}
int DOTCONFDocument::checkConfig(const std::list<DOTCONFDocumentNode*>::iterator & from)
{
int ret = 0;
DOTCONFDocumentNode * tagNode = NULL;
int vi = 0;
for(std::list<DOTCONFDocumentNode*>::iterator i = from; i != nodeTree.end(); i++){
tagNode = *i;
if(!tagNode->closed){
error(tagNode->lineNum, tagNode->fileName, "unclosed tag %s", tagNode->name);
ret = -1;
break;
}
vi = 0;
while( vi < tagNode->valuesCount ){
if(strstr(tagNode->values[vi], "${") && strchr(tagNode->values[vi], '}') ){
ret = macroSubstitute(tagNode, vi );
mempool->free();
if(ret == -1){
break;
}
}
++vi;
}
if(ret == -1){
break;
}
}
return ret;
}
int DOTCONFDocument::setContent(const char * _fileName)
{
int ret = 0;
char realpathBuf[PATH_MAX];
if(realpath(_fileName, realpathBuf) == NULL){
error(0, NULL, "realpath(%s) failed: %s", _fileName, strerror(errno));
return -1;
}
fileName = strdup(realpathBuf);
processedFiles.push_back(strdup(realpathBuf));
if(( file = fopen(fileName, "r")) == NULL){
error(0, NULL, "failed to open file '%s': %s", fileName, strerror(errno));
return -1;
}
ret = parseFile();
(void) fclose(file);
if(!ret){
if( (ret = checkConfig(nodeTree.begin())) == -1){
return -1;
}
std::list<DOTCONFDocumentNode*>::iterator from;
DOTCONFDocumentNode * tagNode = NULL;
int vi = 0;
for(std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin(); i!=nodeTree.end(); i++){
tagNode = *i;
if(!cmp_func("DOTCONFPPIncludeFile", tagNode->name)){
vi = 0;
while( vi < tagNode->valuesCount ){
if(access(tagNode->values[vi], R_OK) == -1){
error(tagNode->lineNum, tagNode->fileName, "%s: %s", tagNode->values[vi], strerror(errno));
return -1;
}
if(realpath(tagNode->values[vi], realpathBuf) == NULL){
error(tagNode->lineNum, tagNode->fileName, "realpath(%s) failed: %s", tagNode->values[vi], strerror(errno));
return -1;
}
bool processed = false;
for(std::list<char*>::const_iterator itInode = processedFiles.begin(); itInode != processedFiles.end(); itInode++){
if(!strcmp(*itInode, realpathBuf)){
processed = true;
break;
}
}
if(processed){
break;
}
processedFiles.push_back(strdup(realpathBuf));
file = fopen(tagNode->values[vi], "r");
if(file == NULL){
error(tagNode->lineNum, fileName, "failed to open file '%s': %s", tagNode->values[vi], strerror(errno));
return -1;
}
fileName = strdup(realpathBuf);
from = nodeTree.end(); --from;
ret = parseFile();
(void) fclose(file);
if(ret == -1)
return -1;
if(checkConfig(++from) == -1){
return -1;
}
++vi;
}
}
}
if(!requiredOptions.empty())
ret = checkRequiredOptions();
}
return ret;
}
int DOTCONFDocument::checkRequiredOptions()
{
for(std::list<char*>::const_iterator ci = requiredOptions.begin(); ci != requiredOptions.end(); ci++){
bool matched = false;
for(std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin(); i!=nodeTree.end(); i++){
if(!cmp_func((*i)->name, *ci)){
matched = true;
break;
}
}
if(!matched){
error(0, NULL, "required option '%s' not specified", *ci);
return -1;
}
}
return 0;
}
void DOTCONFDocument::error(int lineNum, const char * fileName_, const char * fmt, ...)
{
va_list args;
va_start(args, fmt);
size_t len = (lineNum!=0?strlen(fileName_):0) + strlen(fmt) + 50;
char * buf = (char*)mempool->alloc(len);
if(lineNum)
(void) snprintf(buf, len, "DOTCONF++: file '%s', line %d: %s\n", fileName_, lineNum, fmt);
else
(void) snprintf(buf, len, "DOTCONF++: %s\n", fmt);
(void) vfprintf(stderr, buf, args);
va_end(args);
}
char * DOTCONFDocument::getSubstitution(char * macro, int lineNum)
{
char * buf = NULL;
char * variable = macro+2;
char * endBr = strchr(macro, '}');
if(!endBr){
error(lineNum, fileName, "unterminated '{'");
return NULL;
}
*endBr = 0;
char * defaultValue = strchr(variable, ':');
if(defaultValue){
*defaultValue++ = 0;
if(*defaultValue != '-'){
error(lineNum, fileName, "incorrect macro substitution syntax");
return NULL;
}
++defaultValue;
if(*defaultValue == '"' || *defaultValue == '\''){
++defaultValue;
defaultValue[strlen(defaultValue)-1] = 0;
}
} else {
defaultValue = NULL;
}
char * subs = getenv(variable);
if( subs ){
buf = mempool->strdup(subs);
} else {
std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin();
DOTCONFDocumentNode * tagNode = NULL;
for(; i!=nodeTree.end(); i++){
tagNode = *i;
if(!cmp_func(tagNode->name, variable)){
if(tagNode->valuesCount != 0){
buf = mempool->strdup(tagNode->values[0]);
break;
}
}
}
if( i == nodeTree.end() ){
if( defaultValue ){
buf = mempool->strdup(defaultValue);
} else {
error(lineNum, fileName, "substitution not found and default value not given");
return NULL;
}
}
}
return buf;
}
int DOTCONFDocument::macroSubstitute(DOTCONFDocumentNode * tagNode, int valueIndex)
{
int ret = 0;
char * macro = tagNode->values[valueIndex];
size_t valueLen = strlen(tagNode->values[valueIndex])+1;
char * value = (char*)mempool->alloc(valueLen);
char * v = value;
char * subs = NULL;
while(*macro){
if(*macro == '$' && *(macro+1) == '{'){
char * m = strchr(macro, '}');
subs = getSubstitution(macro, tagNode->lineNum);
if(subs == NULL){
ret = -1;
break;
}
macro = m + 1;
*v = 0;
v = (char*)mempool->alloc(strlen(value)+strlen(subs)+valueLen);
strcpy(v, value);
value = strcat(v, subs);
v = value + strlen(value);
continue;
}
*v++ = *macro++;
}
*v = 0;
free(tagNode->values[valueIndex]);
tagNode->values[valueIndex] = strdup(value);
return ret;
}
const DOTCONFDocumentNode * DOTCONFDocument::getFirstNode() const
{
if ( !nodeTree.empty() ) {
return *nodeTree.begin();
} else {
return NULL;
}
}
const DOTCONFDocumentNode * DOTCONFDocument::findNode(const char * nodeName, const DOTCONFDocumentNode * parentNode, const DOTCONFDocumentNode * startNode) const
{
std::list<DOTCONFDocumentNode*>::const_iterator i = nodeTree.begin();
if(startNode == NULL)
startNode = parentNode;
if(startNode != NULL){
while( i != nodeTree.end() && (*i) != startNode ){
++i;
}
if( i != nodeTree.end() ) ++i;
}
for(; i!=nodeTree.end(); i++){
if((*i)->parentNode != parentNode){
continue;
}
if(!cmp_func(nodeName, (*i)->name)){
return *i;
}
}
return NULL;
}
void DOTCONFDocument::setRequiredOptionNames(const char ** requiredOptionNames)
{
while(*requiredOptionNames){
requiredOptions.push_back(strdup( *requiredOptionNames ));
++requiredOptionNames;
}
}

View file

@ -0,0 +1,110 @@
#ifndef DOTCONFPP_H
#define DOTCONFPP_H
#include <list>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef WIN32
#define PATH_MAX _MAX_PATH
#define snprintf _snprintf
#define strcasecmp stricmp
#define realpath(path,resolved_path) _fullpath(resolved_path, path, _MAX_PATH)
#include <io.h>
#else
#include <unistd.h>
#include <limits.h>
#include <stdint.h>
#include <strings.h>
#endif
#include "mempool.h"
class DOTCONFDocument;
class DOTCONFDocumentNode
{
friend class DOTCONFDocument;
private:
DOTCONFDocumentNode * previousNode;
DOTCONFDocumentNode * nextNode;
DOTCONFDocumentNode * parentNode;
DOTCONFDocumentNode * childNode;
char ** values;
int valuesCount;
char * name;
const DOTCONFDocument * document;
int lineNum;
char * fileName;
bool closed;
void pushValue(char * _value);
public:
DOTCONFDocumentNode();
~DOTCONFDocumentNode();
const char * getConfigurationFileName()const { return fileName; }
int getConfigurationLineNumber() const { return lineNum; }
const DOTCONFDocumentNode * getNextNode() const { return nextNode; }
const DOTCONFDocumentNode * getPreviuosNode() const { return previousNode; }
const DOTCONFDocumentNode * getParentNode() const { return parentNode; }
const DOTCONFDocumentNode * getChildNode() const { return childNode; }
const char* getValue(int index = 0) const;
const char * getName() const { return name; }
const DOTCONFDocument * getDocument() const { return document; }
};
class DOTCONFDocument
{
public:
enum CaseSensitive { CASESENSETIVE, CASEINSENSETIVE };
protected:
AsyncDNSMemPool * mempool;
private:
DOTCONFDocumentNode * curParent;
DOTCONFDocumentNode * curPrev;
int curLine;
bool quoted;
std::list<DOTCONFDocumentNode*> nodeTree;
std::list<char*> requiredOptions;
std::list<char*> processedFiles;
FILE * file;
char * fileName;
std::list<char*> words;
int (*cmp_func)(const char *, const char *);
int checkRequiredOptions();
int parseLine();
int parseFile(DOTCONFDocumentNode * _parent = NULL);
int checkConfig(const std::list<DOTCONFDocumentNode*>::iterator & from);
int cleanupLine(char * line);
char * getSubstitution(char * macro, int lineNum);
int macroSubstitute(DOTCONFDocumentNode * tagNode, int valueIndex);
protected:
virtual void error(int lineNum, const char * fileName, const char * fmt, ...) ATTR_PRINTF(4,5);
public:
DOTCONFDocument(CaseSensitive caseSensitivity = CASESENSETIVE);
virtual ~DOTCONFDocument();
int setContent(const char * _fileName);
void setRequiredOptionNames(const char ** requiredOptionNames);
const DOTCONFDocumentNode * getFirstNode() const;
const DOTCONFDocumentNode * findNode(const char * nodeName, const DOTCONFDocumentNode * parentNode = NULL, const DOTCONFDocumentNode * startNode = NULL) const;
};
#endif

View file

@ -0,0 +1,100 @@
#include "mempool.h"
AsyncDNSMemPool::PoolChunk::PoolChunk(size_t _size):
pool(NULL), pos(0), size(_size)
{
pool = ::malloc(size);
}
AsyncDNSMemPool::PoolChunk::~PoolChunk()
{
::free(pool);
}
AsyncDNSMemPool::AsyncDNSMemPool(size_t _defaultSize):
chunks(NULL), chunksCount(0), defaultSize(_defaultSize),
poolUsage(0), poolUsageCounter(0)
{
}
AsyncDNSMemPool::~AsyncDNSMemPool()
{
for(size_t i = 0; i<chunksCount; i++){
delete chunks[i];
}
::free(chunks);
}
int AsyncDNSMemPool::initialize()
{
chunksCount = 1;
chunks = (PoolChunk**)::malloc(sizeof(PoolChunk*));
if(chunks == NULL)
return -1;
chunks[chunksCount-1] = new PoolChunk(defaultSize);
return 0;
}
void AsyncDNSMemPool::addNewChunk(size_t size)
{
++chunksCount;
chunks = (PoolChunk**)::realloc(chunks, chunksCount*sizeof(PoolChunk*));
if(size <= defaultSize)
chunks[chunksCount-1] = new PoolChunk(defaultSize);
else
chunks[chunksCount-1] = new PoolChunk(size);
}
void * AsyncDNSMemPool::alloc(size_t size)
{
PoolChunk * chunk = NULL;
for(size_t i = 0; i<chunksCount; i++){
chunk = chunks[i];
if((chunk->size - chunk->pos) >= size){
chunk->pos += size;
return ((char*)chunk->pool) + chunk->pos - size;
}
}
addNewChunk(size);
chunks[chunksCount-1]->pos = size;
return chunks[chunksCount-1]->pool;
}
void AsyncDNSMemPool::free()
{
size_t pu = 0;
size_t psz = 0;
++poolUsageCounter;
for(size_t i = 0; i<chunksCount; i++){
pu += chunks[i]->pos;
psz += chunks[i]->size;
chunks[i]->pos = 0;
}
poolUsage=(poolUsage>pu)?poolUsage:pu;
if(poolUsageCounter >= 10 && chunksCount > 1){
psz -= chunks[chunksCount-1]->size;
if(poolUsage < psz){
--chunksCount;
delete chunks[chunksCount];
}
poolUsage = 0;
poolUsageCounter = 0;
}
}
void * AsyncDNSMemPool::calloc(size_t size)
{
return ::memset(this->alloc(size), 0, size);
}
char * AsyncDNSMemPool::strdup(const char *str)
{
return ::strcpy((char*)this->alloc(strlen(str)+1), str);
}

View file

@ -0,0 +1,46 @@
#ifndef ASYNC_DNS_MEMPOOL_H
#define ASYNC_DNS_MEMPOOL_H
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#undef free
#undef calloc
#undef strdup
class AsyncDNSMemPool
{
private:
struct PoolChunk {
void * pool;
size_t pos;
size_t size;
PoolChunk(size_t _size);
~PoolChunk();
};
PoolChunk ** chunks;
size_t chunksCount;
size_t defaultSize;
size_t poolUsage;
size_t poolUsageCounter;
void addNewChunk(size_t size);
public:
AsyncDNSMemPool(size_t _defaultSize = 4096);
virtual ~AsyncDNSMemPool();
int initialize();
void free();
void * alloc(size_t size);
void * calloc(size_t size);
char * strdup(const char *str);
};
#endif