X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/8c6fa3fbaccc22127280bf77a48fab5a3ee0716e..46b0747592074017ff0ea4b33d4a7194235886e5:/stglibs/dotconfpp.lib/dotconfpp.cpp diff --git a/stglibs/dotconfpp.lib/dotconfpp.cpp b/stglibs/dotconfpp.lib/dotconfpp.cpp deleted file mode 100644 index 8f766f01..00000000 --- a/stglibs/dotconfpp.lib/dotconfpp.cpp +++ /dev/null @@ -1,664 +0,0 @@ -/* Copyright (C) 2003 Aleksey Krivoshey -* -* 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 // dirname -#include // glob -#include - -#include "stg/dotconfpp.h" -#include "mempool.h" - -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), errorCallback(NULL), errorCallbackData(NULL), - curLine(0), file(NULL), fileName(NULL) -{ - if(caseSensitivity == CASESENSITIVE){ - cmp_func = strcmp; - } else { - cmp_func = strcasecmp; - } - - mempool = new AsyncDNSMemPool(1024); - mempool->initialize(); -} - -DOTCONFDocument::~DOTCONFDocument() -{ - for(std::list::iterator i = nodeTree.begin(); i != nodeTree.end(); ++i){ - delete(*i); - } - for(std::list::iterator i = requiredOptions.begin(); i != requiredOptions.end(); ++i){ - free(*i); - } - for(std::list::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)){ - //printf("2start='%s'\n", 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){ // 'parameter = value' is the same as 'parameter value' but do not replace with ' ' when used in quoted value - *line = ' ';continue; - } - if(*line == '\\' && (*(line+1) == '"' || *(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')){ //multiline - *bg = 0; - if(strlen(start)){ - //printf("3start='%s'\n", 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 == '\''){ //need to handle quotes because of spaces or = that may be between - quoted = !quoted; - line++; continue; - } - if(isspace(*line) && !quoted){ - *bg++ = 0; - if(strlen(start)){ - //printf("start='%s'\n", 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::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 this not <> node then it is closed by default - if(*nodeName == '<'){ - if(*(nodeName+1) != '/'){ //opening tag - nodeName++; - closed = false; - } else { //closing tag - nodeName+=2; - std::list::reverse_iterator i=nodeTree.rbegin(); - for(; i!=nodeTree.rend(); ++i){ - if(!cmp_func(nodeName, (*i)->name) && !(*i)->closed){ - (*i)->closed = true; - curParent = (*i)->parentNode; - curPrev = *i; - break; - } - } - if(i==nodeTree.rend()){ - error(curLine, fileName, "not matched closing tag ", 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; - - while(fgets(str, 511, file)){ - curLine++; - size_t 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::iterator & from) -{ - int ret = 0; - - for(std::list::iterator i = from; i != nodeTree.end(); ++i){ - DOTCONFDocumentNode * tagNode = *i; - if(!tagNode->closed){ - error(tagNode->lineNum, tagNode->fileName, "unclosed tag %s", tagNode->name); - ret = -1; - break; - } - int vi = 0; - while( vi < tagNode->valuesCount ){ - //if((tagNode->values[vi])[0] == '$' && (tagNode->values[vi])[1] == '{' && strchr(tagNode->values[vi], '}') ){ - 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, _fileName, "%s", strerror(errno)); - return -1; - } - - fileName = strdup(realpathBuf); - - char * forPathName = strdup(realpathBuf); - - if (forPathName == NULL) { - error(0, NULL, "Not enought memory to duplicate realpath"); - return -1; - } - - char * _pathName = dirname(forPathName); - - std::string pathName(_pathName); - - free(forPathName); // From strdup - - 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::iterator from; - DOTCONFDocumentNode * tagNode = NULL; - int vi = 0; - for(std::list::iterator i = nodeTree.begin(); i!=nodeTree.end(); ++i){ - tagNode = *i; - if(!cmp_func("IncludeFile", tagNode->name)){ - vi = 0; - while( vi < tagNode->valuesCount ){ - glob_t globBuf; - std::string nodeFilePath; - if (*tagNode->values[vi] != '/') { - // Relative path - nodeFilePath = pathName + "/" + tagNode->values[vi]; - } else { - // Absolute path - nodeFilePath = tagNode->values[vi]; - } - int res = glob(nodeFilePath.c_str(), 0, NULL, &globBuf); - if (res) { - switch (res) { - case GLOB_NOSPACE: - error(tagNode->lineNum, tagNode->fileName, "glob call failed for '%s': no free space", nodeFilePath.c_str()); - return -1; -#ifndef FREE_BSD - case GLOB_ABORTED: - // printf("Read error\n"); - // Ignore that error - break; - case GLOB_NOMATCH: - // printf("No match\n"); - // Ignore that error - break; -#endif - default: - error(tagNode->lineNum, tagNode->fileName, "glob call failed for '%s': unknown error", nodeFilePath.c_str()); - return -1; - } - } - if (!res) { - for (size_t i = 0; i < globBuf.gl_pathc; ++i) { - std::string nodeFilePath(globBuf.gl_pathv[i]); - if(access(nodeFilePath.c_str(), R_OK) == -1){ - error(tagNode->lineNum, tagNode->fileName, "%s: %s", nodeFilePath.c_str(), strerror(errno)); - continue; - } - if(realpath(nodeFilePath.c_str(), realpathBuf) == NULL){ - error(tagNode->lineNum, tagNode->fileName, "realpath(%s) failed: %s", nodeFilePath.c_str(), strerror(errno)); - continue; - } - - bool processed = false; - for(std::list::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(nodeFilePath.c_str(), "r"); - if(file == NULL){ - error(tagNode->lineNum, fileName, "failed to open file '%s': %s", nodeFilePath.c_str(), strerror(errno)); - continue; - } - //free(fileName); - fileName = strdup(realpathBuf); - from = nodeTree.end(); --from; - - if(tagNode->parentNode){ - DOTCONFDocumentNode * nd = tagNode->parentNode->childNode; - while(nd){ - if(!nd->nextNode) - break; - nd = nd->nextNode; - } - - curPrev = nd; - } - ret = parseFile(tagNode->parentNode); - - //ret = parseFile(tagNode->parentNode); - (void) fclose(file); - if(ret == -1) - continue; - if(checkConfig(++from) == -1){ - continue; - } - } - } - globfree(&globBuf); - vi++; - } - } - } - /* - if( (ret = checkConfig(nodeTree.begin())) == -1){ - return -1; - } - */ - - if(!requiredOptions.empty()) - ret = checkRequiredOptions(); - } - - return ret; -} - -int DOTCONFDocument::checkRequiredOptions() -{ - for(std::list::const_iterator ci = requiredOptions.begin(); ci != requiredOptions.end(); ++ci){ - bool matched = false; - for(std::list::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); - - char msg[256]; - - vsnprintf(msg, 256, fmt, args); - - size_t len = (lineNum!=0?strlen(fileName):0) + strlen(msg) + 50; - char * buf = (char*)mempool->alloc(len); - - if(lineNum) - (void) snprintf(buf, len, "File '%s', line %d: %s\n", fileName, lineNum, msg); - else - (void) snprintf(buf, len, "File '%s': %s\n", fileName, msg); - - if (errorCallback) { - errorCallback(errorCallbackData, buf); - } else { - (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::iterator i = nodeTree.begin(); - for(; i!=nodeTree.end(); ++i){ - DOTCONFDocumentNode * 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 -{ - //printf("nodeName=%s, cont=%s, start=%s\n", nodeName, containingNode!=NULL?containingNode->name:"NULL", startNode!=NULL?startNode->name:"NULL"); - - std::list::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(parentNode != NULL && (*i)->parentNode != parentNode){ - 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++; - } -} -