跨平台配置文件类TConfig

这是一个跨平台的配置文件类,它提供了两个接口函数:
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 = &section[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 = &section[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);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值