这是一个跨平台的配置文件类,它提供了两个接口函数:
int ReadString (char* sec, char* key, char* value);
int WriteString (char* sec, char* key, char* value);
用来对文件进行操作。
使用示例(Usage example):
TConfig config("desk.ini");
config.WriteString("network", "ip", "192.168.0.1");
char ip[256];
config.ReadString("network", "ip", ip);
使用注意事项:
调用ReadString时,需要保证第3个参数所分配的空间大于文件中该值的空间,
否则会出现缓冲区溢出,我没有解决掉这个问题,欢迎高手告诉我解决之道。
当然,将这个参数的空间设为256字节(宏LINE_SIZE)是不会出错的。
如果在试用这个类的过程中,出现什么问题,或者你有什么好的想法,欢迎
和我联系或在这里留言,非常感谢。zwj123@163.com
/* TConfig.h */
#if !defined _TCONFIG_H_
#define _TCONFIG_H_
#include <stdio.h>
#define MAX_NODE 32
#define LINE_SIZE 256
#define NULL 0
struct key_node;
struct section_node
{
char *sectionname;
struct key_node* child;
};
struct key_node
{
char *keyname;
char *keyvalue;
struct section_node* parent;
struct key_node* next;
};
class TConfig
{
public:
TConfig(char*);
virtual ~TConfig();
int ReadString (char* sec, char* key, char* value);
int WriteString (char* sec, char* key, char* value);
private:
section_node section[MAX_NODE];
char *filename;
bool dirty; //dirty mark
void initnode();
void removeblank(char *sz, int flag);
int readline(FILE *file, char *linebuf, int offset);
void UpdateFile();
};
#endif
/* TConfig.cpp */
#include <string.h>
#include <stdlib.h>
#include "TConfig.h"
TConfig::TConfig(char* _filename)
{
dirty = false;
filename = new char[strlen(_filename) +1];
strcpy(filename, _filename);
for(int i=0; i<MAX_NODE; ++i)
{
section[i].sectionname = NULL;
section[i].child = NULL;
}
initnode();
}
TConfig::~TConfig()
{
if(dirty)
UpdateFile();
dirty = false;
delete filename;
for(int idx=0; idx<MAX_NODE; ++idx)
{
if(section[idx].sectionname == NULL)
break;
key_node *p, *pre = section[idx].child;
while(pre && pre->next)
{
p = pre->next;
if(p){
pre->next = p->next;
delete p;
}
else
pre->next = NULL;
}
delete section[idx].sectionname;
}
}
void TConfig::initnode()
{
FILE *file;
char linebuf[LINE_SIZE];
int index = -1;
bool bsection = true; //section operation or key operation?
bool bread = true; //whether or read line?
int offset = 0;
struct key_node *p, *prior;
char *pdest;
file = fopen(filename, "r+b");
if(!file)return;
do
{
if(bread)
{
fseek(file, offset, SEEK_SET);
offset = readline(file, linebuf, offset);
removeblank(linebuf, 0);
}
bread = true;
if(bsection)//find section
{
if(linebuf[0] == '[' && linebuf[strlen(linebuf) - 1] == ']')//new section
{
index++;
if(index >= MAX_NODE)break;//the number of section must less than MAX_NODE
int len = strlen(linebuf) - 2; //don't count '['and ']'
section[index].sectionname = new char[len+1];
memcpy(section[index].sectionname, &linebuf[1], len);
section[index].sectionname[len] = '/0';
section[index].child = NULL;
bsection = false; //end finding section
}
else
continue;//continue to find section
}
else
{
if(linebuf[0] == '[' && linebuf[strlen(linebuf) - 1] == ']')//new section?
{
bread = false;//don't to read new line
bsection = true;
continue;
}
pdest = strchr(linebuf, '=');
if(pdest)
{
p = new key_node;
int pos = pdest - linebuf;
removeblank(pdest+1, 0);//filter '='
p->keyvalue = new char[strlen(pdest+1)];
strcpy(p->keyvalue, pdest+1);
linebuf[pos] = '/0';
removeblank(linebuf, 0);
p->keyname = new char[strlen(linebuf)+1];
strcpy(p->keyname, linebuf);
p->parent = §ion[index];
p->next = NULL;
//insert key node
if(section[index].child == NULL)
section[index].child = p;
else
{
prior = section[index].child;
while(prior->next)
{
prior = prior->next;
}
prior->next = p;
}
}
}
}while(offset != -1 || !bread);//file havn't end or must to handle data
if(file)fclose(file);
}
/******************************************
* read one line from file in binary mode
* from offset to '/n '
* return vlaue:
* -1: file end
* others: new offset
******************************************/
int TConfig::readline(FILE *file, char *linebuf, int offset)
{
int idx=0;
char ch;
linebuf[0] = '/0';
for(;;)
{
if(feof(file))break;
ch = getc(file);
offset++;
if(ch == '/n')
{
linebuf[idx - 1] = '/0';//remove '/r'
return offset;
}
linebuf[idx++] = ch;
}
linebuf[idx-1] = '/0';//filter 'EOF' mark
return -1;
}
/*********************************
* remove blank or tab of string
* flag = -1,0,1 : left,both,right
* note: sz length must be less 256
*********************************/
void TConfig::removeblank(char *sz, int flag)
{
int idx = 0;
if(strlen(sz) >= LINE_SIZE)return;
if(flag != 1)
{
char buf[256];
while(sz[idx] == ' ' || sz[idx] == ' ')idx++;
strcpy(buf, &sz[idx]);
strcpy(sz, buf);
}
if(flag != -1)
{
idx = strlen(sz) - 1;
while(sz[idx] == ' ' || sz[idx] == ' ')idx--;
sz[idx+1] = '/0';
}
}
/*********************************************
* return value
* 0 : success
* -1: section cannot find
* -2: key cannot find
*********************************************/
int TConfig::ReadString(char* sec, char* key, char* value)
{
//find section
int i=0;
for(; i<MAX_NODE; ++i)
if(section[i].sectionname ==NULL || strcmp(section[i].sectionname, sec) == 0)
break;
if(section[i].sectionname ==NULL)
return -1;
key_node* p = section[i].child;
while(p)
{
if(strcmp(p->keyname, key) == 0)//find keyname
{
strcpy(value, p->keyvalue); //copy keyvalue to value
return 0;
}
p = p->next;
}
return -2;
}
/*********************************************
* return value
* 0 : success
* -1: too much section
*********************************************/
int TConfig::WriteString(char* sec, char* key, char* value)
{
//find section
int idx=0;
for(; idx<MAX_NODE; ++idx)
if(section[idx].sectionname == NULL || strcmp(section[idx].sectionname, sec) == 0)
break;
if(idx >= MAX_NODE)return -1;
if(section[idx].sectionname == NULL)//new section
{
section[idx].sectionname = new char[strlen(sec)+1];
strcpy(section[idx].sectionname, sec);
}
key_node *p = new key_node;
p->keyname = key;
p->keyvalue = value;
p->next = NULL;
p->parent = §ion[idx];
if(section[idx].child == NULL)
{
section[idx].child = p;
dirty = true;
}
else
{
key_node *pre = section[idx].child;
while(pre->next)
{
if(strcmp(pre->keyname, p->keyname) ==0)
break;
pre = pre->next;
}
if(strcmp(pre->keyname, p->keyname) == 0) //old key
{
if(strcmp(pre->keyvalue, p->keyvalue) !=0) //key equal but vale not equal
{
pre->keyvalue = p->keyvalue;
dirty = true;
}
}
else //new key
{
pre->next = p;
dirty = true;
}
}
if(dirty)UpdateFile();
dirty = false;
return 0;
}
/*************************************
* write list data into file
*************************************/
void TConfig::UpdateFile()
{
FILE *file = fopen(filename, "w+b");
if(!file)return;
char linebuf[LINE_SIZE];
int len;
for(int idx=0; idx<MAX_NODE; ++idx)
{
if(section[idx].sectionname == NULL)
break;
//write section
linebuf[0] = '[';
len = strlen(section[idx].sectionname);
memcpy(&linebuf[1], section[idx].sectionname, len);
linebuf[len+1] = ']';
linebuf[len+2] = '/r';
linebuf[len+3] = '/n';
fwrite(linebuf, len+4, 1, file);
key_node *p = section[idx].child;
while(p)
{
//write key
len = strlen(p->keyname);
strcpy(linebuf, p->keyname);
linebuf[len] = '=';
memcpy(&linebuf[len+1], p->keyvalue, strlen(p->keyvalue));
len = len + 1 + strlen(p->keyvalue);
linebuf[len] = '/r';
linebuf[len+1] = '/n';
fwrite(linebuf, len+2, 1, file);
p=p->next;
}
//write blank line
linebuf[0] = '/r';
linebuf[1] = '/n';
fwrite(linebuf, 2, 1, file);
}
if(file)fclose(file);
}