diff --git a/HISTORY b/HISTORY index 3bce3fd..c800fa6 100644 --- a/HISTORY +++ b/HISTORY @@ -1,4 +1,7 @@ +Version 1.28 2016-06-14 + * ini_file_reader support #@if + Version 1.28 2016-06-08 * id generator support extra bits * change inet_aton to inet_pton diff --git a/libfastcommon.spec b/libfastcommon.spec index 18a06a7..4d56148 100644 --- a/libfastcommon.spec +++ b/libfastcommon.spec @@ -2,7 +2,7 @@ %define LibFastcommonDevel libfastcommon-devel Name: libfastcommon -Version: 1.0.28 +Version: 1.0.29 Release: 1%{?dist} Summary: c common functions library extracted from my open source projects FastDFS License: GPL diff --git a/src/ini_file_reader.c b/src/ini_file_reader.c index 35cb0a7..9c8edc2 100644 --- a/src/ini_file_reader.c +++ b/src/ini_file_reader.c @@ -17,17 +17,38 @@ #include "shared_func.h" #include "logger.h" #include "http_func.h" +#include "local_ip_func.h" #include "ini_file_reader.h" #define _LINE_BUFFER_SIZE 512 #define _INIT_ALLOC_ITEM_COUNT 32 +#define _PREPROCESS_TAG_STR_IF "#@if " +#define _PREPROCESS_TAG_STR_ELSE "#@else" +#define _PREPROCESS_TAG_STR_ENDIF "#@endif" +#define _PREPROCESS_TAG_STR_FOR "#@for " +#define _PREPROCESS_TAG_STR_ENDFOR "#@endfor" + +#define _PREPROCESS_TAG_LEN_IF (sizeof(_PREPROCESS_TAG_STR_IF) - 1) +#define _PREPROCESS_TAG_LEN_ELSE (sizeof(_PREPROCESS_TAG_STR_ELSE) - 1) +#define _PREPROCESS_TAG_LEN_ENDIF (sizeof(_PREPROCESS_TAG_STR_ENDIF) - 1) +#define _PREPROCESS_TAG_LEN_FOR (sizeof(_PREPROCESS_TAG_STR_FOR) - 1) +#define _PREPROCESS_TAG_LEN_ENDFOR (sizeof(_PREPROCESS_TAG_STR_ENDFOR) - 1) + +#define _PREPROCESS_VARIABLE_STR_LOCAL_IP "%{LOCAL_IP}" +#define _PREPROCESS_VARIABLE_STR_LOCAL_HOST "%{LOCAL_HOST}" + +#define _PREPROCESS_VARIABLE_LEN_LOCAL_IP \ + (sizeof(_PREPROCESS_VARIABLE_STR_LOCAL_IP) - 1) +#define _PREPROCESS_VARIABLE_LEN_LOCAL_HOST \ + (sizeof(_PREPROCESS_VARIABLE_STR_LOCAL_HOST) - 1) + static AnnotationMap *g_annotataionMap = NULL; static int remallocSection(IniSection *pSection, IniItem **pItem); static int iniDoLoadFromFile(const char *szFilename, \ IniContext *pContext); -static int iniDoLoadItemsFromBuffer(char *content, \ +static int iniLoadItemsFromBuffer(char *content, \ IniContext *pContext); int iniSetAnnotationCallBack(AnnotationMap *map, int count) @@ -278,7 +299,7 @@ static int iniDoLoadFromFile(const char *szFilename, \ } } - result = iniDoLoadItemsFromBuffer(content, pContext); + result = iniLoadItemsFromBuffer(content, pContext); free(content); return result; @@ -293,7 +314,7 @@ int iniLoadFromBuffer(char *content, IniContext *pContext) return result; } - result = iniDoLoadItemsFromBuffer(content, pContext); + result = iniLoadItemsFromBuffer(content, pContext); if (result == 0) { iniSortItems(pContext); @@ -638,6 +659,293 @@ static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext) return result; } +static char *iniAllocContent(IniContext *pContext, const int content_len) +{ + char *buff; + if (pContext->dynamicContents.count >= pContext->dynamicContents.alloc_count) + { + int alloc_count; + int bytes; + char **contents; + if (pContext->dynamicContents.alloc_count == 0) + { + alloc_count = 8; + } + else + { + alloc_count = pContext->dynamicContents.alloc_count * 2; + } + bytes = sizeof(char *) * alloc_count; + contents = (char **)malloc(bytes); + if (contents == NULL) + { + logError("file: "__FILE__", line: %d, " + "malloc %d bytes fail", __LINE__, bytes); + return NULL; + } + memset(contents, 0, bytes); + if (pContext->dynamicContents.count > 0) + { + memcpy(contents, pContext->dynamicContents.contents, + sizeof(char *) * pContext->dynamicContents.count); + free(pContext->dynamicContents.contents); + } + pContext->dynamicContents.contents = contents; + pContext->dynamicContents.alloc_count = alloc_count; + } + + buff = malloc(content_len); + if (buff == NULL) + { + logError("file: "__FILE__", line: %d, " + "malloc %d bytes fail", __LINE__, content_len); + return NULL; + } + pContext->dynamicContents.contents[pContext->dynamicContents.count++] = buff; + return buff; +} + +static bool iniCalcCondition(char *condition, const int condition_len) +{ + /* + * current only support %{VARIABLE} in [x,y,..] + * support variables are: LOCAL_IP and LOCAL_HOST + * such as: %{LOCAL_IP} in [10.0.11.89,10.0.11.99] + **/ +#define _PREPROCESS_VARIABLE_TYPE_LOCAL_IP 1 +#define _PREPROCESS_VARIABLE_TYPE_LOCAL_HOST 2 +#define _PREPROCESS_MAX_LIST_VALUE_COUNT 32 + char *p; + char *pEnd; + char *values[_PREPROCESS_MAX_LIST_VALUE_COUNT]; + int varType; + int count; + int i; + + pEnd = condition + condition_len; + p = pEnd - 1; + while (p > condition && (*p == ' ' || *p == '\t')) + { + p--; + } + if (*p != ']') + { + logWarning("file: "__FILE__", line: %d, " + "expect \"]\", condition: %.*s", __LINE__, + condition_len, condition); + return false; + } + *p = '\0'; + + p = condition; + while (p < pEnd && (*p == ' ' || *p == '\t')) + { + p++; + } + + if (pEnd - p < 12) + { + logWarning("file: "__FILE__", line: %d, " + "unkown condition: %.*s", __LINE__, + condition_len, condition); + return false; + } + + if (memcmp(p, _PREPROCESS_VARIABLE_STR_LOCAL_IP, + _PREPROCESS_VARIABLE_LEN_LOCAL_IP) == 0) + { + varType = _PREPROCESS_VARIABLE_TYPE_LOCAL_IP; + p += _PREPROCESS_VARIABLE_LEN_LOCAL_IP; + } + else if (memcmp(p, _PREPROCESS_VARIABLE_STR_LOCAL_HOST, + _PREPROCESS_VARIABLE_LEN_LOCAL_HOST) == 0) + { + varType = _PREPROCESS_VARIABLE_TYPE_LOCAL_HOST; + p += _PREPROCESS_VARIABLE_LEN_LOCAL_HOST; + } + else + { + logWarning("file: "__FILE__", line: %d, " + "unkown condition: %.*s", __LINE__, + condition_len, condition); + return false; + } + + while (p < pEnd && (*p == ' ' || *p == '\t')) + { + p++; + } + if (pEnd - p < 4 || memcmp(p, "in", 2) != 0) + { + logWarning("file: "__FILE__", line: %d, " + "expect \"in\", condition: %.*s", __LINE__, + condition_len, condition); + return false; + } + + while (p < pEnd && (*p == ' ' || *p == '\t')) + { + p++; + } + if (*p != '[') + { + logWarning("file: "__FILE__", line: %d, " + "expect \"[\", condition: %.*s", __LINE__, + condition_len, condition); + return false; + } + + count = splitEx(p+1, ',', values, _PREPROCESS_MAX_LIST_VALUE_COUNT); + if (varType == _PREPROCESS_VARIABLE_TYPE_LOCAL_HOST) + { + char host[128]; + if (gethostname(host, sizeof(host)) != 0) + { + logWarning("file: "__FILE__", line: %d, " + "call gethostname fail, " + "errno: %d, error info: %s", __LINE__, + errno, STRERROR(errno)); + return false; + } + } + else + { + const char *local_ip; + local_ip = get_first_local_ip(); + while (local_ip != NULL) + { + for (i=0; i pEnd) + { + ifPartLen = pEnd - pIfPart; + pElsePart = NULL; + elsePartLen = 0; + } + else + { + ifPartLen = pElse - pIfPart; + pElsePart = strchr(pElse + _PREPROCESS_TAG_LEN_ELSE, '\n'); + if (pElsePart == NULL) + { + return content; + } + + elsePartLen = pEnd - pElsePart; + } + + newContent = iniAllocContent(pContext, content_len); + if (newContent == NULL) + { + return NULL; + } + + pDest = newContent; + copyLen = pStart - content; + if (copyLen > 0) + { + memcpy(pDest, content, copyLen); + pDest += copyLen; + } + + if (iniCalcCondition(pCondition, conditionLen)) + { + if (ifPartLen > 0) + { + memcpy(pDest, pIfPart, ifPartLen); + pDest += ifPartLen; + } + } + else + { + if (elsePartLen > 0) + { + memcpy(pDest, pElsePart, elsePartLen); + pDest += elsePartLen; + } + } + + copyLen = (content + content_len) - (pEnd + _PREPROCESS_TAG_LEN_ENDIF); + if (copyLen > 0) + { + memcpy(pDest, pEnd + _PREPROCESS_TAG_LEN_ENDIF, copyLen); + pDest += copyLen; + } + + *pDest = '\0'; + *new_content_len = pDest - newContent; + return newContent; +} + +static int iniLoadItemsFromBuffer(char *content, IniContext *pContext) +{ + char *pContent; + char *new_content; + int content_len; + int new_content_len; + + new_content = content; + new_content_len = strlen(content); + + do + { + pContent = new_content; + content_len = new_content_len; + if ((new_content=iniProccessIf(pContent, content_len, + pContext, &new_content_len)) == NULL) + { + return ENOMEM; + } + } while (new_content != pContent); + + return iniDoLoadItemsFromBuffer(new_content, pContext); +} + static int remallocSection(IniSection *pSection, IniItem **pItem) { int bytes, result; @@ -699,6 +1007,7 @@ static int iniFreeHashData(const int index, const HashData *data, void *args) void iniFreeContext(IniContext *pContext) { + int i; if (pContext == NULL) { return; @@ -712,6 +1021,19 @@ void iniFreeContext(IniContext *pContext) hash_walk(&pContext->sections, iniFreeHashData, NULL); hash_destroy(&pContext->sections); + + if (pContext->dynamicContents.contents != NULL) + { + for (i=0; idynamicContents.count; i++) + { + if (pContext->dynamicContents.contents[i] != NULL) + { + free(pContext->dynamicContents.contents[i]); + } + } + free(pContext->dynamicContents.contents); + pContext->dynamicContents.contents = NULL; + } } diff --git a/src/ini_file_reader.h b/src/ini_file_reader.h index 2a586ee..dfc6688 100644 --- a/src/ini_file_reader.h +++ b/src/ini_file_reader.h @@ -52,6 +52,11 @@ typedef struct IniSection *current_section; //for load from ini file char config_path[MAX_PATH_SIZE]; //save the config filepath bool ignore_annotation; + struct { + int count; + int alloc_count; + char **contents; + } dynamicContents; //dynamic alloced contents which will be freed when destroy } IniContext; #ifdef __cplusplus