DS_xx工具

来源:互联网 发布:lca算法 pascal 编辑:程序博客网 时间:2024/05/09 07:43
 /*
************************************************************************************
************************************************************************************
************************************************************************************
***************************         ds. h          ***************************************
************************************************************************************
************************************************************************************

*/

 

 

#ifndef __DS_H__
#define __DS_H__

#include <stdio.h>

#define DS_SIZE_CONTENT      4096
#define DS_SIZE_UNIT      64
#define DS_SIZE_PRE_COMMENT     1024
#define DS_SIZE_POST_COMMENT    1024
#define DS_MAX_ENTRY      10000
#define DS_MAX_ENTRY_INT     10000
#define DS_SIZE_ERROR      4096
#define DS_SIZE_RD       6144 

#define DS_IGNORE_CASE      1 
#define DS_IGNORE_PUNCT      2
#define DS_IGNORE_CASE_AND_PUNCT 3

typedef struct
{
 unsigned int id;
 char content[DS_SIZE_CONTENT];
 char unit[DS_SIZE_UNIT];
 char pre_comment[DS_SIZE_PRE_COMMENT];
 char post_comment[DS_SIZE_POST_COMMENT];  //default = \n

}DS, *PDS, **PPDS;

typedef struct
{
 PPDS pDSS;    
 unsigned int num;     //the number of PDS
 PPDS pDSS_int;
 unsigned int num_int;    //the number of PDS insert
 unsigned int id_pointer;   //id_pointer+1 is inserted next.
 unsigned int id_auto;    //id auto increase
 char error[DS_SIZE_ERROR];
 int char_mode;     //case: 1 ignore case, 2 ignore punctuation, 3 ignore case and punctuation

}DS_BLOCK, *PDS_BLOCK;


/*===============    initialization and ending   ========================*/
/************************************************************************/
/* 初始化文件块句柄
 参数:
  PDS_BLOCK p_b  文件块句柄
 返回值:
  NULL 失败 
  其他: 成功
                                                                        */
/************************************************************************/
PDS_BLOCK ds_init();
/************************************************************************/
/* 释放文件块句柄
 参数:
  PDS_BLOCK p_b  文件块句柄
 返回值:
  无
                                                                        */
/************************************************************************/
void ds_end(PDS_BLOCK p_b);

 

/*======================     read-write   ==============================*/
/************************************************************************/
/* 读取文件
 参数:
  PDS_BLOCK p_b  文件块句柄
  char* file_name     文件名
 返回值:
  0  成功
  其它 失败
                                                                        */
/************************************************************************/
int ds_read(PDS_BLOCK p_b, char *file_name);
/************************************************************************/
/* 写入文件
 参数:
  PDS_BLOCK p_b  文件块句柄
  char* file_name     文件名
 返回值:
  0  成功
  其它 失败
                                                                        */
/************************************************************************/
int ds_write(PDS_BLOCK p_b, char *file_name, char *mode);
/************************************************************************/
/* 追加写入文件
 参数:
  PDS_BLOCK p_b  文件块句柄
  char* file_name     文件名
  PDS p_ds  条目
 返回值:
  0  成功
  其它 失败
                                                                        */
/************************************************************************/
int ds_write_entry(PDS_BLOCK p_b, char *file_name, char *mode, PDS p_ds);

 

/*=========================     search    ==============================*/
/************************************************************************/
/* 根据ID查询条目
 参数:
  PDS_BLOCK p_b  文件块句柄
  unsigned int id     ID
  PPDS pp_ds  返回条目
 返回值:
  0  查询成功
  1  查询不到
  其它 查询失败
                                                                        */
/************************************************************************/
int ds_search_id(PDS_BLOCK p_b, unsigned int id, PPDS pp_ds);
/************************************************************************/
/* 根据内容查询条目(不区分大小)
 参数:
  PDS_BLOCK p_b  文件块句柄
  char *p_content  内容
  char *p_unit        单位
  PPDS pp_ds  返回条目
 返回值:
  0  查询成功
  1  查询不到
  其它 查询失败
                                                                        */
/************************************************************************/
int ds_search_content_unit(PDS_BLOCK p_b, char *p_content, char *p_unit, PPDS pp_ds);

 

/*=========================     insert    ==============================*/
/************************************************************************/
/* 根据ID、内容插入条目
 参数:
  PDS_BLOCK p_b  文件块句柄
  unsigned int id  ID
  char *p_content  内容
  char *p_unit        单位
  PPDS pp_ds  返回插入成功或已存在的条目
 返回值:
  0  插入成功
  其它 插入失败
                                                                        */
/************************************************************************/
int ds_insert_id_content_unit(PDS_BLOCK p_b, unsigned int id, char *p_content, char*p_unit, PPDS pp_ds);
/************************************************************************/
/* 根据内容插入条目,ID自增、内容不能重复
   需先调用ds_set_id_pointer设置,插入的位置
 参数:
  PDS_BLOCK p_b  文件块句柄
  char *p_content  内容
  char *p_unit        单位
  PPDS pp_ds  返回插入成功或已存在的条目
 返回值:
  0  插入成功
  其它 插入失败
                                                                        */
/************************************************************************/
int ds_insert_auto(PDS_BLOCK p_b, char *p_content, char *p_unit, PPDS pp_ds);
/************************************************************************/
/* 根据条目插入,id、内容不能重复
 参数:
  PDS_BLOCK p_b  文件块句柄
  PDS p_ds  待插入的条目
 返回值:
  0  插入成功
  其它 插入失败
                                                                        */
/************************************************************************/
int ds_insert_entry(PDS_BLOCK p_b, PDS p_ds);

 


/*=========================     delete   ==============================*/
/************************************************************************/
/* 根据ID删除
 参数:
  PDS_BLOCK p_b  文件块句柄
  unsigned int id  ID
 返回值:
  0  删除成功
  其它 删除失败
                                                                        */
/************************************************************************/
int ds_delete_id(PDS_BLOCK p_b, unsigned int id);

 


/*=========================     replace   ==============================*/
/************************************************************************/
/* 根据ID替换
 参数:
  PDS_BLOCK p_b  文件块句柄
  unsigned int id, ID
  PDS p_ds  条目
 返回值:
  0  替换成功
  其它 替换失败
                                                                        */
/************************************************************************/
int ds_replace_id(PDS_BLOCK p_b, unsigned int id, PDS p_ds);
/************************************************************************/
/* 根据条目替换
 参数:
  PDS_BLOCK p_b  文件块句柄
  PDS p_ds  条目
 返回值:
  0  替换成功
  其它 替换失败
                                                                        */
/************************************************************************/
int ds_replace_entry(PDS_BLOCK p_b, PDS p_ds);

 


/*========================       sort   =============================*/
/************************************************************************/
/* 正向排序:注意只排序p_b的pDSS部分
 参数:
  PDS_BLOCK p_b  文件块句柄
 返回值:
  无
                                                                        */
/************************************************************************/
void ds_sort(PDS_BLOCK p_b);
/************************************************************************/
/* 正向排序PPDS pTexts
 参数:
  PPDS pTexts  DS数据
  unsigned int num PDS的个数
 返回值:
  无
                                                                        */
/************************************************************************/
void ds_sort_ppds(PPDS pDSS, unsigned int num);

 

/*========================       merge   =============================*/
/************************************************************************/
/* 合并:将p_b的pDSS_int部分合并到p_b的pDSS
 参数:
  PDS_BLOCK p_b  文件块句柄
 返回值:
  0  成功
  其它 失败
                                                                        */
/************************************************************************/
int ds_merge(PDS_BLOCK p_b);

 

/*===============    getter and setter   ========================*/
/************************************************************************/
/* 设置ID指针,条目被插入到ID+1位置
 参数:
  PDS_BLOCK p_b  文件块句柄
  unsigned int id_auto  ID
 返回值:
  无
                                                                        */
/************************************************************************/
void ds_set_id_auto(PDS_BLOCK p_b, unsigned int id_auto);
/************************************************************************/
/* 读取id_auto
 参数:
  PDS_BLOCK p_b  文件块句柄
 返回值:
  ID指针
                                                                        */
/************************************************************************/
unsigned int ds_get_id_auto(PDS_BLOCK p_b);
/************************************************************************/
/* 设置ID指针,条目被插入到ID+1位置
 参数:
  PDS_BLOCK p_b  文件块句柄
  unsigned int id_pointer  ID
 返回值:
  无
                                                                        */
/************************************************************************/
void ds_set_id_pointer(PDS_BLOCK p_b, unsigned int id_pointer);
/************************************************************************/
/* 读取当前ID指针
 参数:
  PDS_BLOCK p_b  文件块句柄
 返回值:
  ID指针
                                                                        */
/************************************************************************/
unsigned int ds_get_id_pointer(PDS_BLOCK p_b);
/************************************************************************/
/* 获取错误信息
 参数:
  PDS_BLOCK p_b  文件块句柄
 返回值:
  错误信息
                                                                        */
/************************************************************************/
char* ds_get_err(PDS_BLOCK p_b);
/************************************************************************/
/* 清除错误信息
 参数:
  PDS_BLOCK p_b  文件块句柄
 返回值:
  无
                                                                        */
/************************************************************************/
void ds_clr_err(PDS_BLOCK p_b);

 

/************************************************************************/
/* 设置大小写
 参数:
  PDS_BLOCK p_b  文件块句柄
  char_mode             #define DS_IGNORE_CASE      1 
             #define DS_IGNORE_PUNCT      2
             #define DS_IGNORE_CASE_AND_PUNCT 3
 返回值:
  ID指针
                                                                        */
/************************************************************************/
void ds_set_search_mode(PDS_BLOCK p_b, int char_mode);


#endif

/*
************************************************************************************
************************************************************************************
************************************************************************************
***************************         ds. c          ***************************************
************************************************************************************
************************************************************************************

*/

#include "ds.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*============     function prototype    ================*/
static char*  quote_position  (char *pdata);
static void   write_a_entry  (FILE *fp, PDS p_ds);
void    ignore_punctuation (char *str);

//     ========================       //
//        getter and setter           //
//     ========================       //

void ds_set_id_auto(PDS_BLOCK p_b, unsigned int id_auto)
{
 if (NULL == p_b)
  return;
 p_b->id_auto = id_auto;
}

unsigned int ds_get_id_auto(PDS_BLOCK p_b)
{
 if (NULL == p_b)
  return 0xFFFFFFFF;
 return p_b->id_auto;
}

void ds_set_id_pointer(PDS_BLOCK p_b, unsigned int id_pointer)
{
 if (NULL == p_b)
  return;
 p_b->id_pointer = id_pointer;
}

unsigned int ds_get_id_pointer(PDS_BLOCK p_b)
{
 if (NULL == p_b)
  return 0xFFFFFFFF;
 return p_b->id_pointer;
}

char* ds_get_err(PDS_BLOCK p_b)
{
 if (NULL == p_b)
  return "PDS_BLOCK is NULL.\n";
 else
  return &p_b->error[0];
}

void ds_clr_err(PDS_BLOCK p_b)
{
 p_b->error[0] = '\0';
}

//     ========================       //
//        extern function             //
//     ========================       //

PDS_BLOCK ds_init()
{
 PDS_BLOCK p_b = NULL;
 p_b = malloc(sizeof(DS_BLOCK));
 if (NULL == p_b)
 {
  return NULL;
 }
 memset(p_b, 0, sizeof(DS_BLOCK));
 
 p_b->pDSS = malloc(DS_MAX_ENTRY * sizeof(PDS));
 if (NULL == p_b->pDSS)
 {
  free(p_b);
  return NULL;
 }

 p_b->pDSS_int = malloc(DS_MAX_ENTRY_INT * sizeof(PDS));
 if (NULL == p_b->pDSS_int)
 {
  free(p_b->pDSS);
  free(p_b);
  return NULL;
 }

 memset(p_b->pDSS,  0,  DS_MAX_ENTRY * sizeof(PDS));
 memset(p_b->pDSS_int, 0,  DS_MAX_ENTRY_INT * sizeof(PDS));

 p_b->id_pointer = 0xFFFFFFFF;

 return p_b;
}

 

void ds_end(PDS_BLOCK p_b)
{
 unsigned int i = 0;

 if (NULL == p_b)
  return;

 for (i=0; i<p_b->num; i++)
 {
  free(p_b->pDSS[i]);
  p_b->pDSS[i] = 0;
 }
 p_b->num = 0;
 
 for (i=0; i<p_b->num_int; i++)
 {
  free(p_b->pDSS_int[i]);
  p_b->pDSS_int[i] = 0;
 }
 p_b->num_int = 0;

 free(p_b->pDSS_int);
 p_b->pDSS_int = 0;

 free(p_b->pDSS);
 p_b->pDSS = 0;

 free(p_b);
 p_b = 0;
}


/********
1.skip comment line and blank line
2.identify data line : 0x??,0x??
3.read id : 0x??,0x??
4.read content and unit
*********/
int ds_read(PDS_BLOCK p_b, char *file_name)
{
 FILE *fp = NULL;
 unsigned int id = 0;
 int ret = 0;
 long row_no = 0;
 int pos[4] = {0};
 char *p = NULL;
 char *p_quote = NULL;   //first quote
 char *p_post = NULL;   //post comment
 char *p_content = NULL;   //content
 char *p_unit = NULL;   //unit
 char read[DS_SIZE_RD] = {0};
 char comment[DS_SIZE_PRE_COMMENT] = {0};  //pre-comment
 char err[100] = {0};
 char err_buf[DS_SIZE_ERROR] = {0};


 if (NULL == p_b)
  return -1;
 if (NULL == file_name)
 {
  sprintf(p_b->error, "Parameter error.\n");
  return -1;  
 }
 
 //__asm{INT 3};
 if (NULL == (fp=fopen(file_name, "rt")))
 {
  sprintf(p_b->error, "Can not open %s.\n", file_name);
  return -1;
 }

 ds_clr_err(p_b);
 for (row_no=1; !feof(fp); row_no++)
 {
#if defined _DEBUG
  printf("Row no %d.\n", row_no);
#endif

  if (p_b->num >= DS_MAX_ENTRY)
  {
   sprintf(err, "More than %d entries.\n", DS_MAX_ENTRY);
   strcat(p_b->error, err);
   fclose(fp);
   return -1;
  }

   if (NULL == fgets(read, sizeof(read), fp))  // only EOF
  {
   if (feof(fp))
    break;
   sprintf(err, "Read file data error.\n");
   strcat(p_b->error, err);
   fclose(fp);
   return -1;
  }

  if (NULL==strchr(read, '\n') && !feof(fp))     // '\n' may be not in the last line.
  { 
   sprintf(err, "Row %d: Too long line.\n", row_no);
   strcat(err_buf, err);
   while(NULL!=fgets(read, sizeof(read), fp) || !feof(fp))
   {
    if (NULL != strchr(read, '\n'))
     break;
   }
   ret = -1;
   continue;
  }

  if ('0' != read[0])  // empty row   or   pure comment row,    because data line begine with 0x??,0x??
  {     //settle pre-comment
   p = &read[0];
   while (' '==*p || '\t'==*p)
    p++;

   if ('\n'!=*p && ';'!=*p)
   {
    sprintf(err, "Row %d: Unknown row format.\n", row_no);
    strcat(err_buf, err);
    ret = -1;
    continue;
   }

   if (strlen(comment)+strlen(p) > sizeof(comment)-2)
   {
    sprintf(err, "Row %d: Too long pre-omment.\n", row_no);
    strcat(err_buf, err);
    ret = -1;
    continue;
   }
   strcat(comment, p); 
  }
  else                   //entry row
  {      //settle data
   pos[3] = -1;
   pos[2] = -1;
   pos[1] = -1;
   pos[0] = -1;
   sscanf(&read[0], "%2x,%2x,%2x,%2x,", &pos[3], &pos[2], &pos[1], &pos[0]);   // Not very strict, but it always work well.
   if (pos[3]>0x100 || pos[3]<0 ||
    pos[2]>0x100 || pos[2]<0 ||
    pos[1]>0x100 || pos[1]<0 ||
    pos[0]>0x100 || pos[0]<0)
   {
    sprintf(err, "Row %d: ID error.\n", row_no);
    strcat(err_buf, err);
    comment[0] = '\0';
    ret = -1;
    continue;
   }
   id = (pos[3]<<24) + (pos[2]<<16) + (pos[1]<<8) + (pos[0]);

   p = &read[20];
   while (' '==*p || '\t'==*p)
    p++;

   if ('\"' != *p)
   {
    sprintf(err, "Row %d: Not a quote follows ID.\n", row_no);
    strcat(err_buf, err);
    comment[0] = '\0';
    ret = -1;
    continue;
   }

   p_quote = quote_position(p);   //search next speech mark
   if (NULL == p_quote)
   {
    sprintf(err, "Row %d: Quote error.\n", row_no);
    strcat(err_buf, err);
    comment[0] = '\0';
    ret = -1;
    continue;
   }

   p_content = p+1;
   *p_quote = '\0'; 
   if (strlen(p_content) > DS_SIZE_CONTENT-1)
   {
    sprintf(err, "Row %d: Too long content.\n", row_no);
    strcat(err_buf, err);
    comment[0] = '\0';
    ret = -1; 
    continue;
   }

   p = p_quote+1;
   while (' '==*p || '\t'==*p)
    p++;

   if ('\"' != *p)
   {
    sprintf(err, "Row %d: Not a quote follows Content.\n", row_no);
    strcat(err_buf, err);
    comment[0] = '\0';
    ret = -1;
    continue;
   }

   p_quote = quote_position(p);   //search next speech mark
   if (NULL == p_quote)
   {
    sprintf(err, "Row %d: Quote error in Unit.\n", row_no);
    strcat(err_buf, err);
    comment[0] = '\0';
    ret = -1;
    continue;
   }

   p_unit = p+1;  //unit begin
   *p_quote = '\0'; 
   if (strlen(p_unit) > DS_SIZE_UNIT-1)
   {
    sprintf(err, "Row %d: Too long unit.\n", row_no);
    strcat(err_buf, err);
    comment[0] = '\0';
    ret = -1; 
    continue;
   }

   p_post = p_quote+1;    //post comment begin
   while (' '==*p_post || '\t'==*p_post)
    p_post++;

   if ('\n'!=*p_post && ';'!=*p_post)
   {
    if (!feof(fp))
    {
     sprintf(err, "Row %d: Error occurs behind unit.\n", row_no);
     strcat(err_buf, err);
     comment[0] = '\0';
     ret = -1; 
     continue;
    }
   }

   p_post = p_quote+1;    //post comment begin
   if (feof(fp) && NULL==strchr(p_post, '\n'))
    strcat(p_post, "\n");

   if (strlen(p_post) > DS_SIZE_POST_COMMENT-1)
   {
    sprintf(err, "Row %d: Too long post-comment.\n", row_no);
    strcat(err_buf, err);
    comment[0] = '\0';
    ret = -1;
    continue;
   }

   if (0 == ds_search_id(p_b, id, NULL))
   {
    sprintf(err, "Row %d: ID has existed.\n", row_no);
    strcat(err_buf, err);
    comment[0] = '\0';
    ret = -1;
    continue;
   }

   p_b->pDSS[p_b->num] = malloc(sizeof(DS));
   if (0 == p_b->pDSS[p_b->num])
   {
    sprintf(p_b->error, "Allocate dynamic memory fail.\n");
    fclose(fp);
    return -1;
   }
   memset(p_b->pDSS[p_b->num], 0, sizeof(DS));

   p_b->pDSS[p_b->num]->id = id;
   strcpy(p_b->pDSS[p_b->num]->content, p_content);
   strcpy(p_b->pDSS[p_b->num]->unit, p_unit);
   if ('\0' != comment[0])   // write pre-comment first
   {
    strcpy(p_b->pDSS[p_b->num]->pre_comment, comment);
    comment[0] = '\0';
   }
   strcpy(p_b->pDSS[p_b->num]->post_comment, p_post);   
  
   p_b->num++;   
  } // end of if ('0' != read[0])
 } // end of while (!feof(fp))
 fclose(fp);

 strcpy(p_b->error, err_buf);

 return ret;
}

 

int ds_write(PDS_BLOCK p_b, char *file_name, char *mode)
{
 FILE *fp = NULL;
 unsigned int i = 0;
 unsigned int insert_index = 0;
 
 if (NULL == p_b)
  return -1;
  
 if (NULL == file_name)
 {
  sprintf(p_b->error, "Parameter error.\n");
  return -1;  
 }

 if (0xFFFFFFFF == p_b->id_pointer)  //insert into the last
  insert_index = p_b->num;
 else
 { //search where to insert
  for (i=0; i<p_b->num; i++)
  {
   if (p_b->pDSS[i]->id == p_b->id_pointer)
   {
    insert_index = i+1;
    break;
   }
  }
  if (i == p_b->num)
  {
   sprintf(p_b->error, "Id pointer %d is not exist.\n", p_b->id_pointer);
   return -1;
  }
 }

 if (NULL==mode || 0==strcmp(mode, "wt"))
  fp = fopen(file_name, "wt");
 else if(0 == strcmp(mode, "at"))
 {  
  fp = fopen(file_name, mode);//"wt"  "at"
 }
 else
 {
  sprintf(p_b->error, "Open mode error.\n");
  return -1;
 }
 if (NULL == fp) 
 {
  sprintf(p_b->error, "Can not open %s.\n", file_name);
  return -1;
 } 
 if(mode!=NULL && 0==strcmp(mode, "at"))
  fseek(fp, SEEK_END, 0);
 
 for (i=0; i<insert_index; i++)
 {
  write_a_entry(fp, p_b->pDSS[i]);
 }

 for (i=0; i<p_b->num_int; i++)
 {
  write_a_entry(fp, p_b->pDSS_int[i]);
 }

 for (i=insert_index; i<p_b->num; i++)
 {
  write_a_entry(fp, p_b->pDSS[i]);
 }

 fclose(fp);

 return 0;
}


int ds_write_entry(PDS_BLOCK p_b, char *file_name, char *mode, PDS p_ds)
{
 FILE *fp = NULL;
 
 if (NULL==p_b)
  return -1;
  
 if (NULL==file_name)
 {
  sprintf(p_b->error, "Parameter error.\n");
  return -1;  
 }
 
 if (NULL==mode || 0==strcmp(mode, "wt"))
  fp = fopen(file_name, "wt");
 else if(0 == strcmp(mode, "at"))
 {  
  fp = fopen(file_name, mode);//"wt"  "at"
 }
 else
 {
  sprintf(p_b->error, "Open mode error.\n");
  return -1;
 }
 if (NULL == fp) 
 {
  sprintf(p_b->error, "Can not open %s.\n", file_name);
  return -1;
 } 
 if(mode!=NULL && 0==strcmp(mode, "at"))
  fseek(fp, SEEK_END, 0); 
 
 write_a_entry(fp, p_ds);

 fclose(fp);
 return 0;
}


//
int ds_search_id(PDS_BLOCK p_b, unsigned int id, PPDS pp_ds)
{
 unsigned int i = 0;

 if (NULL==p_b)
 {
  return -1;
 }

 for (i=0; i<p_b->num; i++)
 {
  if (id == p_b->pDSS[i]->id)
  {
   if (NULL != pp_ds)
    *pp_ds =  p_b->pDSS[i];
   return 0;
  }
 }

 for (i=0; i<p_b->num_int; i++)
 {
  if (id == p_b->pDSS_int[i]->id)
  {
   if (NULL != pp_ds)
    *pp_ds =  p_b->pDSS_int[i];
   return 0;
  }
 }
 
 sprintf(p_b->error, "Can not find the entry with the same id.\n");
 return 1;
}

 

int ds_search_content_unit(PDS_BLOCK p_b, char *p_content, char *p_unit, PPDS pp_ds)
{
 unsigned int i = 0;
 char *p1 = NULL;  //p_content  bak
 char *p2 = NULL;  //p_content  bak
 char *p3 = NULL;  //p_unit   bak
 char *p4 = NULL;  //p_unit   bak

 if (NULL==p_b)
  return -1;

 if (NULL==p_content || NULL==p_unit)
 {
  sprintf(p_b->error, "Parameter error.\n");
  return -1;  
 } 
 
 if (p_b->char_mode)
 {
  p1 = malloc(strlen(p_content)+1);
  if (NULL == p1)
  {
   sprintf(p_b->error, "Allocate dynamic memory fail.\n");
   return -1;
  }
  strcpy(p1, p_content);
  if (DS_IGNORE_CASE==p_b->char_mode || DS_IGNORE_CASE_AND_PUNCT==p_b->char_mode)
   strupr(p1);
  if (DS_IGNORE_PUNCT==p_b->char_mode || DS_IGNORE_CASE_AND_PUNCT==p_b->char_mode)
   ignore_punctuation(p1);

  p3 = malloc(strlen(p_unit)+1);
  if (NULL == p3)
  {
   sprintf(p_b->error, "Allocate dynamic memory fail.\n");
   free(p1);
   p1 = NULL;
   return -1;
  }
  strcpy(p3, p_unit);
  if (DS_IGNORE_CASE==p_b->char_mode || DS_IGNORE_CASE_AND_PUNCT==p_b->char_mode)
   strupr(p3);
 }
 else
 {  //id case and punct
  p1 = p_content;
  p3 = p_unit;
 }

 for (i=0; i<p_b->num; i++)
 {
  if (p_b->char_mode)
  {
   p2 = malloc(strlen(p_b->pDSS[i]->content) + 1);
   if (NULL == p2)
   {
    sprintf(p_b->error, "Allocate dynamic memory fail.\n");
    free(p1);
    free(p3);
    p1 = NULL;
    p3 = NULL;
    return -1;
   }
   strcpy(p2, p_b->pDSS[i]->content);
   if (DS_IGNORE_CASE==p_b->char_mode || DS_IGNORE_CASE_AND_PUNCT==p_b->char_mode)
    strupr(p2);
   if (DS_IGNORE_PUNCT==p_b->char_mode || DS_IGNORE_CASE_AND_PUNCT==p_b->char_mode)
    ignore_punctuation(p2);

   p4 = malloc(strlen(p_b->pDSS[i]->unit) + 1);
   if (NULL == p4)
   {
    sprintf(p_b->error, "Allocate dynamic memory fail.\n");
    free(p1);
    free(p2);
    free(p3);
    p1 = NULL;
    p2 = NULL;
    p3 = NULL;
    return -1;
   }
   strcpy(p4, p_b->pDSS[i]->unit);
   if (DS_IGNORE_CASE==p_b->char_mode || DS_IGNORE_CASE_AND_PUNCT==p_b->char_mode)
    strupr(p4);
  }
  else
  {
   p2 = p_b->pDSS[i]->content;
   p4 = p_b->pDSS[i]->unit;
  }

  if (0==strcmp(p1, p2) && 0==strcmp(p3, p4))
  {
   if (NULL != pp_ds) 
    *pp_ds = p_b->pDSS[i];
   if (p_b->char_mode)
   {
    free(p1);
    free(p2);
    free(p3);
    free(p4);
    p1 = NULL;
    p2 = NULL;
    p3 = NULL;
    p4 = NULL;
   }
   return 0;
  }
  if (p_b->char_mode)
  {
   free(p2);
   free(p4);
   p2 = NULL;
   p4 = NULL;
  }
 }

 for (i=0; i<p_b->num_int; i++)
 {
  if (p_b->char_mode)
  {
   p2 = malloc(strlen(p_b->pDSS_int[i]->content) + 1);
   if (NULL == p2)
   {
    sprintf(p_b->error, "Allocate dynamic memory fail.\n");
    free(p1);
    free(p3);
    p1 = NULL;
    p3 = NULL;
    return -1;
   }
   strcpy(p2, p_b->pDSS_int[i]->content);
   if (DS_IGNORE_CASE==p_b->char_mode || DS_IGNORE_CASE_AND_PUNCT==p_b->char_mode)
    strupr(p2);
   if (DS_IGNORE_PUNCT==p_b->char_mode || DS_IGNORE_CASE_AND_PUNCT==p_b->char_mode)
    ignore_punctuation(p2);

   p4 = malloc(strlen(p_b->pDSS_int[i]->unit) + 1);
   if (NULL == p4)
   {
    sprintf(p_b->error, "Allocate dynamic memory fail.\n");
    free(p1);
    free(p2);
    free(p3);
    p1 = NULL;
    p2 = NULL;
    p3 = NULL;
    return -1;
   }
   strcpy(p4, p_b->pDSS_int[i]->unit);
   if (DS_IGNORE_CASE==p_b->char_mode || DS_IGNORE_CASE_AND_PUNCT==p_b->char_mode)
    strupr(p4);
  }
  else
  {
   p2 = p_b->pDSS_int[i]->content;
   p4 = p_b->pDSS_int[i]->unit;
  }

  if (0==strcmp(p1, p2) && 0==strcmp(p3, p4))
  {
   if (NULL != pp_ds)
    *pp_ds = p_b->pDSS_int[i];
   if (p_b->char_mode)
   {
    free(p1);
    free(p2);
    free(p3);
    free(p4);
    p1 = NULL;
    p2 = NULL;
    p3 = NULL;
    p4 = NULL;
   }
   return 0;
  }
  if (p_b->char_mode)
  {
   free(p2);
   free(p4);
   p2 = NULL;
   p4 = NULL;
  }
 }

 if (p_b->char_mode)
 {
  free(p1);
  free(p3);
  p1 = NULL;
  p3 = NULL;
 }
 
 sprintf(p_b->error, "Can not find the entry with same content.\n"); 
 return 1;
}

 

int ds_insert_id_content_unit(PDS_BLOCK p_b, unsigned int id, char *p_content, char*p_unit, PPDS pp_ds)
{
 int ret = 0;
  
 if (NULL == p_b)
  return -1;  

 if (NULL==p_content || NULL==p_unit)
 {
  sprintf(p_b->error, "Parameter error.\n");
  return -1; 
 }

 if (p_b->num_int >= DS_MAX_ENTRY_INT)
 {
  sprintf(p_b->error, "DS_MAX_ENTRY_INT is not enough.\n");
  return -1;
 }
 
 if ((ret=ds_search_id(p_b, id, pp_ds)) < 0) //error happens in search module, so already has error information
  return ret;
 if (0 == ret)
 {
  sprintf(p_b->error, "Entry's id has already existed.\n");    
  return -1;
 }

 if ((ret=ds_search_content_unit(p_b, p_content, p_unit, pp_ds)) < 0) //error happens in search module, so already has error information
  return ret;
 if (0 == ret)
 {
  sprintf(p_b->error, "Entry's content or unit has already existed.\n");    
  return -1;
 } 
 
 if (strlen(p_content) > DS_SIZE_CONTENT-1)
 {
  sprintf(p_b->error, "Too long content.\n");    
  return -1;
 }

 if (strlen(p_unit) > DS_SIZE_UNIT-1)
 {
  sprintf(p_b->error, "Too long unit.\n");    
  return -1;
 }

 p_b->pDSS_int[p_b->num_int] = malloc(sizeof(DS));
 if (0 == p_b->pDSS_int[p_b->num_int])
 {
  sprintf(p_b->error, "Allocate dynamic memory fail.\n");
  return -1;
 }
 memset(p_b->pDSS_int[p_b->num_int], 0, sizeof(DS));

 p_b->pDSS_int[p_b->num_int]->id = id;
 strcpy(p_b->pDSS_int[p_b->num_int]->content, p_content);
 strcpy(p_b->pDSS_int[p_b->num_int]->unit, p_unit);

 if (NULL != pp_ds)
  *pp_ds = p_b->pDSS_int[p_b->num_int];
 p_b->num_int++;

 return 0;
}

 


int ds_insert_auto(PDS_BLOCK p_b, char *p_content, char *p_unit, PPDS pp_ds)
{
 if (NULL==p_b)
  return -1;

 if (NULL==p_content || NULL==p_unit)
 {
  sprintf(p_b->error, "Parameter error.\n");
  return -1; 
 }

 if (0xFFFFFFFF == p_b->id_auto)
 {
  sprintf(p_b->error, "ID overflows.\n");
  return -1;
 }

 if (0 == ds_insert_id_content_unit(p_b, p_b->id_auto+1, p_content, p_unit, pp_ds))
 {
  p_b->id_auto++;
  return 0;
 }
 else
  return -1;
}

 

int ds_insert_entry(PDS_BLOCK p_b, PDS p_ds)
{
 int ret = 0;
 
 if (NULL == p_b)
  return -1;  

 if (NULL == p_ds)
 {
  sprintf(p_b->error, "Parameter error.\n");
  return -1; 
 }

 if (p_b->num_int >= DS_MAX_ENTRY_INT)
 {
  sprintf(p_b->error, "DS_MAX_ENTRY_INT is not enough.\n");
  return -1;
 }
 
 if ((ret=ds_search_id(p_b, p_ds->id, NULL)) < 0) //error happens in search module, so already has error information
  return ret;
 if (0 == ret)
 {
  sprintf(p_b->error, "Entry's id has already existed.\n");    
  return -1;
 }

 if ((ret=ds_search_content_unit(p_b, p_ds->content, p_ds->unit, NULL)) < 0) //error happens in search module, so already has error information
  return ret;
 if (0 == ret)
 {
  sprintf(p_b->error, "Entry's content or unit has already existed.\n");    
  return -1;
 } 

 p_b->pDSS_int[p_b->num_int] = malloc(sizeof(DS));
 if (0 == p_b->pDSS_int[p_b->num_int])
 {
  sprintf(p_b->error, "Allocate dynamic memory fail.\n");
  return -1;
 }
 memcpy(p_b->pDSS_int[p_b->num_int], p_ds, sizeof(DS));

 p_b->num_int++;

 return 0;
}

 

int ds_delete_id(PDS_BLOCK p_b, unsigned int id)
{
 unsigned int i = 0;

 if (NULL == p_b)
  return -1;  

 for (i=0; i<p_b->num; i++)
 {
  if (id == p_b->pDSS[i]->id)
   break;
 }
 if (i != p_b->num)
 {
  free(p_b->pDSS[i]);
  for (; i<p_b->num; i++)
   p_b->pDSS[i] = p_b->pDSS[i+1];
  p_b->num--;
  return 0;
 }

 for (i=0; i<p_b->num_int; i++)
 {
  if (id == p_b->pDSS_int[i]->id)
   break;
 }
 if (i != p_b->num_int)
 {
  free(p_b->pDSS_int[i]);
  for (; i<p_b->num_int; i++)
   p_b->pDSS_int[i] = p_b->pDSS_int[i+1];
  p_b->num_int--;
  return 0;
 }

 sprintf(p_b->error, "ID can not be found.\n");
 return -1; 
}

 

int ds_replace_id(PDS_BLOCK p_b, unsigned int id, PDS p_ds)
{
 PDS p = NULL;

 if (NULL == p_b)
  return -1; 
 if (NULL == p_ds)
 {
  sprintf(p_b->error, "Parameter error.\n");
  return -1; 
 }

 if (0 != ds_search_id(p_b, id, &p))
  return -1;   

 if (id!=p_ds->id && 0==ds_search_id(p_b, p_ds->id, NULL))
 {
  sprintf(p_b->error, "PDS->ID has already existed.\n");
  return -1;  
 }
 
 memcpy(p, p_ds, sizeof(DS));
 return 0;
}

 

int ds_replace_entry(PDS_BLOCK p_b, PDS p_ds)
{
 return ds_replace_id(p_b, p_ds->id, p_ds);
}

 

void ds_sort(PDS_BLOCK p_b)
{
 if (NULL == p_b)
  return; 

 if (NULL == p_b->pDSS)
 {
  sprintf(p_b->error, "Parameter error.\n");
  return;
 }
 
 ds_sort_ppds(p_b->pDSS, p_b->num);
}

 

void ds_sort_ppds(PPDS pDSS, unsigned int num)
{
 unsigned i = 0;
 unsigned j = 0;
 PDS p_temp = NULL;

 if (NULL == pDSS)
  return;

 for (i=0; i<num; i++)   //fast sort
 {
  for (j=i+1; j<num; j++)
  {
   if (pDSS[i]->id > pDSS[j]->id)
   {
    p_temp = pDSS[i];
    pDSS[i] = pDSS[j];
    pDSS[j] = p_temp;
   }
  }
 }
}
 


int ds_merge(PDS_BLOCK p_b)
{
 unsigned int i = 0;
 unsigned int insert_index = 0;
 unsigned int offset = 0;

 if (NULL == p_b)
  return -1;

 offset = p_b->num_int;
 
 if (p_b->num + p_b->num_int > DS_MAX_ENTRY)
 {
  sprintf(p_b->error, "More than %d entries.\n", DS_MAX_ENTRY);
  return -1;
 }

 if (0xFFFFFFFF == p_b->id_pointer)
  insert_index = p_b->num;
 else
 {
  for (i=0; i<p_b->num; i++)
  {
   if (p_b->pDSS[i]->id == p_b->id_pointer)
   {
    insert_index = i+1;
    break;
   }
  }
  if (i == p_b->num)
  {
   sprintf(p_b->error, "Id pointer %d is not exist.\n", p_b->id_pointer);
   return -1;
  }
 }

 if (0 != p_b->num)
 {
  for (i=p_b->num-1; i>=insert_index; i--) //ending data first, avoid overwrite
  {
   p_b->pDSS[i+offset] = p_b->pDSS[i];
  }
 }
 
 for (i=0; i<offset; i++)
 {
  p_b->pDSS[insert_index+i] = p_b->pDSS_int[i];
  p_b->pDSS_int[i] = NULL;
 }

 p_b->num += p_b->num_int;
 p_b->num_int = 0;
 p_b->id_pointer = 0xFFFFFFFF;
 
 return 0;
}


/*******
#define DS_IGNORE_CASE     1
#define DS_IGNORE_PUNCT     2
#define DS_IGNORE_CASE_AND_PUNCT  3
*****/
void ds_set_search_mode(PDS_BLOCK p_b, int char_mode)
{
 if (NULL != p_b)
  p_b->char_mode = char_mode;
}

 

//     ========================       //
//         inner function             //
//     ========================       //
/******************
1. search first ", except for \"
return NULL:  can not be found
******************/
char* quote_position(char *pdata)
{
 if (NULL == pdata) 
  return NULL;
 do
 {
  pdata++;
  pdata = strchr(pdata, '\"');
  if (NULL == pdata)
   return NULL;
 }
 while ('\\' == *(pdata-1));    
 
 return pdata;
}
/****************
write a entry
*****************/
void write_a_entry(FILE *fp, PDS p_ds)
{
 fputs(&p_ds->pre_comment[0], fp);   

 fprintf(fp, "0x%02X,0x%02X,0x%02X,0x%02X,\t\"",  //id + tab + quote
    (unsigned char)(p_ds->id>>24),
    (unsigned char)(p_ds->id>>16),
    (unsigned char)(p_ds->id>>8),
    (unsigned char)(p_ds->id));

 fputs(p_ds->content, fp);    
 fputs("\"\t\"", fp);
 fputs(p_ds->unit, fp);
 fputs("\"", fp);

 fputs(p_ds->post_comment, fp);
 
 if (NULL == strchr(p_ds->post_comment, '\n'))
  fputs("\n", fp); 
}
/****************
ignoring punctuation
*****************/
char punctuations[20] = {' ', '\t', ',', '.', '_', '?', '!', '(', ')', '\0'};
void ignore_punctuation(char *str)
{
 char *copy = str;
 int i = 0;

 while (*copy != '\0')
 {
  for (i=0; punctuations[i]!='\0'; i++)
  {
   if (*copy == punctuations[i])
    break;
  }
  if ('\0' != punctuations[i])
  {
   copy++;
   continue;
  }

  if ('\\'==*copy && ('t'==*(copy+1) || 'n'==*(copy+1) || 'T'==*(copy+1) || 'N'==*(copy+1)) )
  {
   copy += 2;
   continue;
  }

  *str++ = *copy++;
 }
 *str++ = '\0';
}