1 Star 0 Fork 6

PerryHu / Tiny ini file parser

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
tiny_ini_file.c 20.50 KB
一键复制 编辑 原始数据 按行查看 历史
玄道公子 提交于 2016-10-08 12:35 . Add source codes
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
/*
* MIT License
*
* Copyright (c) 2016 wen.gu <454727014@qq.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/***************************************************************************
* Name: tiny_ini_file.c
*
* Purpose: ini file operation API implementation
*
* Developer:
* wen.gu , 2016-08-10
*
* TODO:
*
***************************************************************************/
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include "tiny_ini_file.h"
/***************************************************************************
*
* macro define
*
***************************************************************************/
#define LOGI printf
#define LOGE printf
/***************************************************************************
*
* data structure define
*
***************************************************************************/
struct key_value_pair_s
{
char* key;
char* value;
void* opaque; /** private data, user cann't modify it */
};
/** ini file parser */
typedef struct my_tiny_ini_file_s
{
tiny_ini_file_t common;
FILE* fp; /** ini file handle */
ini_section_t* sections;
GU32 section_count;
}my_ini_file_t;
/***************************************************************************
*
* API define
*
***************************************************************************/
static inline GBOL isCommentTag(char ch)
{
return (ch == '#' || ch == ';') ? GTRUE : GFALSE;
}
static ini_section_t* iniFileNewSection(const char* name)
{
ini_section_t* isec = NULL;
GU32 len = strlen(name);
char* buf = (char*)malloc(sizeof(ini_section_t) + len + 1);
if (buf)
{
isec = (ini_section_t*)buf;
memset(isec, 0, sizeof(ini_section_t));
isec->name = buf + sizeof(ini_section_t);
memcpy(isec->name, name, len);
isec->name[len] = '\0';
}
else
{
LOGE("alloc section instance failed\n");
}
return isec;
}
static key_value_pair_t* iniFileNewParameter(char* key, GU32 key_len,
char* value, GU32 value_len)
{
key_value_pair_t* param = NULL;
GU32 totalSize = key_len + value_len;
char* buf = (char*)malloc(totalSize + sizeof(key_value_pair_t)+2);
if (buf)
{
param = (key_value_pair_t*)buf;
buf += sizeof(key_value_pair_t);
param->key = buf;
memcpy(buf, key, key_len);
buf[key_len] = '\0';
param->value = buf + key_len + 1;
memcpy(param->value, value, value_len);
buf[totalSize + 1] = '\0';
param->opaque = NULL;
}
else
{
LOGE("alloc buffer for key and value failed\n");
}
return param;
}
static GS32 iniFileAddParameter(ini_section_t* section, key_value_pair_t* param)
{
key_value_pair_t* pair = section->pairs;
if (pair)
{
while (pair->opaque) pair = (key_value_pair_t*)(pair->opaque);
pair->opaque = param;
}
else
{
/** first parameter */
section->pairs = param;
}
section->pair_count++;
return G_OK;
}
static GS32 iniFileAddSection(my_ini_file_t* mif, ini_section_t* section)
{
ini_section_t* isec = mif->sections;
if (isec)
{
while (isec->opaque) isec = (ini_section_t*)isec->opaque;
isec->opaque = section;
}
else
{
/**first section */
mif->sections = section;
}
mif->section_count++;
return G_OK;
}
static GBOL iniFileHasSection_l(my_ini_file_t* mif, const char* name)
{
GBOL ret = GFALSE;
ini_section_t* isec = mif->sections;
while (isec)
{
if (!strcmp(isec->name, name))
{
ret = GTRUE;
break;
}
isec = (ini_section_t*)isec->opaque;
}
return ret;
}
static ini_section_t* iniFileGetSection_l(my_ini_file_t* mif, const char* name)
{
ini_section_t* ret = NULL;
ini_section_t* isec = mif->sections;
while (isec)
{
if (!strcmp(isec->name, name))
{
ret = isec;
break;
}
isec = (ini_section_t*)isec->opaque;
}
return ret;
}
static ini_section_t* iniFileGetNewestSection(my_ini_file_t* mif)
{
ini_section_t* isec = mif->sections;
if (isec)
{
while (isec->opaque) isec = (ini_section_t*)isec->opaque;
}
return isec;
}
static char* iniFileParseSection(my_ini_file_t* mif, char* line,
char* line_end, GU32 line_num, GS32* ret)
{
char* ptr = line;
char* pEnd = line_end;
char* section = strchr(ptr, ']');
/** process section name */
if (section)
{
//char temp = *section;
//*section = '\0';
if (iniFileHasSection_l(mif, ptr) == GTRUE)
{
LOGE("syntax error[line:%d]: section(%s) already exist, end parse \n",
line_num, ptr);
ptr = pEnd;
*ret = G_ErrorUndefined;
}
else
{
char* pLeft = ptr;
char* pRight = section - 1;
/** trim left white-space */
while (isspace(*pLeft) && *pLeft) pLeft++;
/** trim right white-space */
while (isspace(*pRight) && pRight >= pLeft) pRight--;
*(pRight + 1) = '\0';
ini_section_t* isec = iniFileNewSection(pLeft);
if (isec)
{
GS32 result = iniFileAddSection(mif, isec);
if (G_OK == result)
{
ptr = section + 1; /** + 1 indicate skip character ']' */
}
else
{
free(isec); /** release resource */
LOGE("add secition(%s) to list failed(0x%08x)\n", pLeft, *ret);
ptr = pEnd;
*ret = result;
}
}
else
{
LOGE("create section(%s) failed\n", pLeft);
ptr = pEnd;
*ret = G_ErrorInsufficientResources;
}
}
}
else
{
LOGE("syntax error[line:%d]: section doesn't end with ']'\n", line_num);
ptr = pEnd;
*ret = G_ErrorUndefined;
}
return ptr;
}
static char* iniFileParseParameter(ini_section_t* section, char* line,
char* line_end,GU32 line_num, GS32* ret)
{
char* ptr = line;
char* pEnd = line_end;
char* key_end = strchr(ptr, '=');
if (key_end)
{
char* pRight = key_end - 1;
/** strip right white-space */
while (isspace(*pRight) && pRight >= ptr) pRight--;
GU32 key_len = (pRight + 1) - ptr;
char* key = ptr;
char* value = key_end + 1; /** + 1 indicate skip character '=' */
/** strip left white-space */
while (isspace(*value) && value < pEnd) value++;
if (value < pEnd)
{
/** find value end */
char* value_end = value;
/** strip ritght white-space and comment after the value of parameter */
while ((!isspace(*value_end) && (isCommentTag(*value_end) == GFALSE)) &&
(value_end < pEnd))
{
value_end++;
}
if (value_end > value)
{
GU32 value_len = value_end - value;
key_value_pair_t* pair = iniFileNewParameter(key, key_len, value, value_len);
if (pair)
{
iniFileAddParameter(section, pair);
ptr = value_end;
}
else
{
ptr = pEnd;
*ret = G_ErrorInsufficientResources;
}
}
else
{
LOGE("syntax error: the value of parameter is empty(right of \'=\')\n");
ptr = pEnd;
*ret = G_ErrorUndefined;
}
}
else
{
LOGE("syntax error[line:%d]: the value of parameter is empty(right of \'=\')\n", line_num);
ptr = pEnd;
*ret = G_ErrorUndefined;
}
}
else
{
LOGE("syntax error[line:%d]: not complete key, doesn't find end character \'=\' \n", line_num);
ptr = pEnd;
*ret = G_ErrorUndefined;
}
return ptr;
}
static GS32 iniFileParseLine(my_ini_file_t* mif, char* line, GU32 length, GU32 line_num)
{
char* ptr = line;
char* pEnd = line + length;
GS32 ret = G_OK;
while (ptr < pEnd)
{
while (isspace(*ptr)) ptr++; /** skip white-space */
char ch = *ptr;
if (isCommentTag(ch) == GTRUE)
{
/** skip component */
ptr = pEnd;
}
else if (ch == '[')
{
/** ++ indicate skip character '[' */
ptr = iniFileParseSection(mif, ++ptr, pEnd, line_num, &ret);
}
else if (ch == '\0') /** line end */
{
/**do nothing */
}
else
{
if (mif->section_count == 0)
{
/** alloc default section */
ini_section_t* isec = iniFileNewSection(DEFAULT_SECTION_NAME);
if (isec)
{
ret = iniFileAddSection(mif, isec);
if (G_OK != ret)
{
LOGE("add section to list failed(0x%08x)\n", ret);
free(isec);
break;
}
}
else
{
ret = G_ErrorInsufficientResources;
break;
}
}
/**
* current section aways is the newest section ?
* TODO, this case is aways right?
*/
ptr = iniFileParseParameter(iniFileGetNewestSection(mif),
ptr, pEnd, line_num, &ret);
}
}
return ret;
}
static GS32 iniFileParseFile(my_ini_file_t* mif, FILE* fp)
{
GS32 ret = G_OK;
GU32 line_num = 0;
char line_buf[LINE_BUF_MAX_LEN] = { 0 };
while (fgets(line_buf, LINE_BUF_MAX_LEN, fp))
{
line_num++;
ret = iniFileParseLine(mif, line_buf, strlen(line_buf), line_num);
if (G_OK != ret)
{
LOGE("parse line failed\n");
break;
}
}
return ret;
}
static GS32 iniFileLoad(tiny_ini_file_t* ini_file, const char* file_name)
{
GS32 ret = G_ErrorBadParameter;
my_ini_file_t* mif = (my_ini_file_t*)ini_file;
if (file_name)
{
if (ini_file->is_loaded == GFALSE)
{
FILE* fp = fopen(file_name, "r");
if (fp)
{
ret = iniFileParseFile(mif, fp);
if (G_OK == ret)
{
mif->fp = fp;
ini_file->is_loaded = GTRUE;
}
else
{
fclose(fp);
}
}
else
{
LOGE("open ini file(%s) failed(%d, %s)\n", file_name, errno, strerror(errno));
}
}
else
{
LOGE("already load one file, cann't load more\n");
ret = G_ErrorInvalidOperation;
}
}
return ret;
}
static GS32 iniFileGetValue(struct tiny_ini_file_s* ini_file, const char* section,
const char* key, char** value)
{
GS32 ret = G_ErrorBadParameter;
my_ini_file_t* mif = (my_ini_file_t*)ini_file;
if (section && key && value)
{
ini_section_t* isec = iniFileGetSection_l(mif, section);
if (isec)
{
if (isec->pairs)
{
char* retValue = NULL;
key_value_pair_t* param = isec->pairs;
while (param)
{
if (!strcmp(param->key, key))
{
retValue = param->value;
break;
}
param = (key_value_pair_t*)param->opaque;
}
if (retValue)
{
*value = retValue;
ret = G_OK;
}
else
{
LOGE("not find the parameter which key is(%s), in section(%s)\n",
key, section);
ret = G_ErrorNotFound;
}
}
else
{
LOGE("nothing in this section(%s)\n", section);
ret = G_ErrorUndefined;
}
}
else
{
LOGE("not find secontion(%s)\n", section);
ret = G_ErrorNotFound;
}
}
return ret;
}
static GS32 iniFileGetValues(struct tiny_ini_file_s* ini_file, const char* section,
const char* key, char** values[], GU32* count)
{
GS32 ret = G_ErrorBadParameter;
my_ini_file_t* mif = (my_ini_file_t*)ini_file;
if (section && key && values && count)
{
ini_section_t* isec = iniFileGetSection_l(mif, section);
if (isec)
{
if (isec->pairs)
{
GU32 getCount = 0;
GU32 arraySize = 0;
key_value_pair_t* param = isec->pairs;
char** valueArray = NULL;
while (param)
{
if (!strcmp(param->key, key))
{
if (getCount >= arraySize)
{
GU32 newSize = arraySize + 4;
GU32 elementSize = sizeof(char*);
char** newArray = (char**)realloc(valueArray, newSize * elementSize);
if (newArray)
{
arraySize = newSize;
valueArray = newArray;
}
else
{
LOGE("realloc value array failed(oldSize:%d, new:%d)\n",
arraySize* elementSize, newSize * elementSize);
ret = G_ErrorInsufficientResources;
getCount = 0;
break;
}
}
valueArray[getCount++] = param->value;
}
param = (key_value_pair_t*)param->opaque;
}
if (getCount)
{
*values = valueArray;
*count = getCount;
ret = G_OK;
}
else
{
LOGE("not find the parameter which key is(%s), in section(%s)\n",
key, section);
ret = G_ErrorNotFound;
}
}
else
{
LOGE("nothing in this section(%s)\n", section);
ret = G_ErrorUndefined;
}
}
else
{
LOGE("not find secontion(%s)\n", section);
ret = G_ErrorNotFound;
}
}
return ret;
}
static void iniFileFreeValues(struct tiny_ini_file_s* ini_file, char* values[], GU32 count)
{
free(values);
/** todo somethings */
}
static GS32 iniFileGetSection(struct tiny_ini_file_s* ini_file, const char* name, ini_section_t** section)
{
GS32 ret = G_ErrorBadParameter;
if (name && section)
{
*section = iniFileGetSection_l((my_ini_file_t*)ini_file, name);
ret = *section ? G_OK : G_ErrorNotFound;
}
return ret;
}
static GBOL iniFileHasKey(struct tiny_ini_file_s* ini_file, const char* section, const char* key)
{
GBOL ret = GFALSE;
if (key && section)
{
ini_section_t* isec = iniFileGetSection_l((my_ini_file_t*)ini_file, section);
if (isec)
{
key_value_pair_t* param = isec->pairs;
while (param)
{
if (!strcmp(param->key, key))
{
ret = GTRUE;
break;
}
param = (key_value_pair_t*)param->opaque;
}
}
else
{
LOGE("not find section(%s)\n", section);
}
}
return ret;
}
static GBOL iniFileHasSection(struct tiny_ini_file_s* ini_file, const char* section)
{
GBOL ret = GFALSE;
if (section)
{
ret = iniFileHasSection_l((my_ini_file_t*)ini_file, section);
}
return ret;
}
static void iniFileDump(struct tiny_ini_file_s* ini_file)
{
my_ini_file_t* mif = (my_ini_file_t*)ini_file;
ini_section_t* isec = mif->sections;
while (isec)
{
LOGI("\nsection: %s, item_count:%d\n", isec->name, isec->pair_count);
key_value_pair_t* param = isec->pairs;
while (param)
{
LOGI("%s = %s \n", param->key, param->value);
param = (key_value_pair_t*)param->opaque;
}
isec = (ini_section_t*)isec->opaque;
}
}
static void iniFileDestroy(struct tiny_ini_file_s* ini_file)
{
my_ini_file_t* mif = (my_ini_file_t*)ini_file;
ini_section_t* isec = mif->sections;
while (isec)
{
key_value_pair_t* param = isec->pairs;
while (param)
{
key_value_pair_t* temp = param;
param = (key_value_pair_t*)param->opaque;
free(temp); /** free a parameter */
}
ini_section_t* temp = isec;
isec = (ini_section_t*)isec->opaque;
free(temp); /** free a section */
}
if (mif->fp)
{
fclose(mif->fp);
}
free(mif); /** free ini file instance */
}
//////////////////////////////////////////////////////////////////////////
GS32 TinyIniFileCreate(tiny_ini_file_t** ini_file)
{
GS32 ret = G_OK;
my_ini_file_t* mif = (my_ini_file_t*)malloc(sizeof(my_ini_file_t));
if (mif)
{
memset(mif, 0, sizeof(my_ini_file_t));
tiny_ini_file_t* inf = (tiny_ini_file_t*)mif;
inf->load = iniFileLoad;
inf->getValue = iniFileGetValue;
inf->getValues = iniFileGetValues;
inf->freeValues = iniFileFreeValues;
inf->getSection = iniFileGetSection;
inf->hasKey = iniFileHasKey;
inf->hasSection = iniFileHasSection;
inf->dump = iniFileDump;
inf->destroy = iniFileDestroy;
inf->is_loaded = GFALSE;
*ini_file = inf;
}
else
{
LOGE("alloc ini file instance failed\n");
ret = G_ErrorInsufficientResources;
}
return ret;
}
C
1
https://gitee.com/Perry0531/Tiny-ini-file-parser.git
git@gitee.com:Perry0531/Tiny-ini-file-parser.git
Perry0531
Tiny-ini-file-parser
Tiny ini file parser
master

搜索帮助