纯C语言INI文件解析

jopen 10年前

  在一个跨平台( Android 、Windows、Linux )项目中配置文件用 INI 格式,自己写了个解析库,纯C语言的,简单好用。

    可以解析 INI 格式的字符串、解析文件、保存到文件。

    下面是头文件:

#ifndef INI_PARSER_H  #define INI_PARSER_H  #ifdef __cplusplus  extern "C" {  #endif  struct tag_value_list;    struct ini_parser {      struct tag_value_list * keyvalues;      int (*parse_file)(struct ini_parser *, const char * file);      int (*parse_string)(struct ini_parser *, const char *text);      char * (*value)(struct ini_parser *, const char * key);      void (*set_value)(struct ini_parser *, const char * key, const char * value);      void (*remove)(struct ini_parser *, const char *key);      int (*save_to_file)(struct ini_parser *, const char * file);  };    struct ini_parser * new_ini_parser();  void delete_ini_parser(struct ini_parser *);    #ifdef __cplusplus  }  #endif  #endif // INI_PARSER_H
下面是源文件:
#include "ini_parser.h"  #include <stdio.h>  #include <string.h>  #include "tag_value.h"    static struct tag_value_pair * parse_line(char *line, int len)  {      struct tag_value_pair * pair = 0;      int count = 0;      char * p = line;      char * end = 0;      char * start = line;      if(!p) return 0;      while(*p == ' ') p++;          /*blank line*/      if(p - line == len ||              *p == '\r' ||              *p == '\n' ||              *p == '\0') return 0;        /*do not support group*/      if(*p == '[') return 0;      /*comments*/      if(*p == '#') return 0;        /* extract key */      start = p;      end = line + len;      while(*p != '=' && p!= end) p++;      if(p == end)      {          /* none '=' , invalid line */          return 0;      }      end = p - 1;      while(*end == ' ') end--; /* skip blank at the end */      count = end - start + 1;        pair = new_tag_value_pair();      pair->szTag = malloc(count + 1);      strncpy(pair->szTag, start, count);      pair->szTag[count] = 0;        /* extract value */      p++;      end = line + len; /* next pos of the last char */      while( *p == ' ' && p != end) p++;      if(p == end)      {          delete_tag_value_pair(pair);          return 0;      }      start = p;      end--; /* to the last char */      if(*end == '\n') { *end = 0; end--; }      if(*end == '\r') { *end = 0; end--; }      count = end - start + 1;      if(count > 0)      {          pair->szValue = malloc(count + 1);          strncpy(pair->szValue, start, count);          pair->szValue[count] = 0;      }        /* release empty key-value pair */      if(!pair->szValue)      {          delete_tag_value_pair(pair);          return 0;      }        return pair;  }    static int _parse_file(struct ini_parser * ini, const char *file){      FILE * fp = fopen(file, "r");      if(fp)      {          struct tag_value_pair * pair = 0;          char buf[1024] = {0};          while(fgets(buf, 1024, fp))          {              pair = parse_line(buf, strlen(buf));              if(pair)              {                  ini->keyvalues->add(ini->keyvalues, pair);              }          }          fclose(fp);          return ini->keyvalues->size;      }      return -1;  }    static int _parse_text(struct ini_parser * ini, const char * text){      char *p = text;      char * start = 0;      struct tag_value_pair * pair = 0;      if(!text) return -1;        while(1)      {          start = p;          while(*p != '\n' && *p != '\0' )p++;          if(*p == '\0') break;            pair = parse_line(start, p - start);          if(pair) ini->keyvalues->add(ini->keyvalues, pair);            p++;      }        return ini->keyvalues->size;  }    static char * _value(struct ini_parser * ini, const char * key){      struct tag_value_pair * pair = ini->keyvalues->find_by_tag(ini->keyvalues, key);      if(pair) return pair->szValue;      return 0;  }    static void _set_value(struct ini_parser * ini, const char * key, const char *value){      struct tag_value_pair * pair = ini->keyvalues->find_by_tag(ini->keyvalues, key);      if(pair)      {          if(pair->szValue) free(pair->szValue);          pair->szValue = strdup(value);      }      else      {          ini->keyvalues->add(ini->keyvalues, make_tag_value_pair(key, value));      }  }    static void _remove(struct ini_parser * ini, const char * key){      struct tag_value_pair * pair = ini->keyvalues->find_by_tag(ini->keyvalues, key);      if(pair)ini->keyvalues->remove(ini->keyvalues, pair);  }    static void write_keyvalue(struct tag_value_pair * pair, FILE *fp)  {      fputs(pair->szTag, fp);      fputc('=', fp);      fputs(pair->szValue, fp);      fputc('\n', fp);  }    static int _save_to_file(struct ini_parser * ini, const char * file){      if(ini->keyvalues->size > 0)      {          FILE * fp = fopen(file, "w");          if(fp)          {              struct tag_value_pair * pair = ini->keyvalues->head;              while(pair != ini->keyvalues->tail)              {                  write_keyvalue(pair, fp);                  pair = pair->next;              }                if(pair)write_keyvalue(pair, fp);                fclose(fp);              return 0;          }      }      return -1;  }    struct ini_parser * new_ini_parser(){      struct ini_parser * ini = (struct ini_parser*)malloc(sizeof(struct ini_parser));      ini->keyvalues = new_tag_value_list();      ini->parse_file = _parse_file;      ini->parse_string = _parse_text;      ini->value = _value;      ini->set_value = _set_value;      ini->remove = _remove;      ini->save_to_file = _save_to_file;      return ini;  }    void delete_ini_parser(struct ini_parser *ini){      if(ini)      {          delete_tag_value_list(ini->keyvalues);          free(ini);      }  }
    测试代码:
#include "util/ini_parser.h"  #include "ini_test.h"  #include <stdio.h>  #include <assert.h>    static char * g_szIniString = "#abc\nfirst=2\nsecond\nname=charli  zhang \n";    static void ini_parser_test_string()  {      struct ini_parser * ini = new_ini_parser();      int size = ini->parse_string(ini, g_szIniString);        assert( size > 0);      assert( ini->value(ini, "second") == 0 );      assert( ini->value(ini, "abc") == 0);      assert( ini->value(ini, "name") != NULL );      assert( ini->value(ini, "first") != NULL);        printf("ini string: %s\n", g_szIniString);      printf("key-value pairs count = %d\n", size);      printf("key \'name\'', value = %s\n", ini->value(ini, "name"));      printf("key \'first\'', value = %s\n", ini->value(ini, "first"));        ini->set_value(ini, "baidu", "hahaha");      ini->save_to_file(ini, "write.conf");        ini->remove(ini, "first");      ini->save_to_file(ini, "write2.conf");        delete_ini_parser(ini);  }    static void ini_parser_test_file()  {      struct ini_parser * ini = new_ini_parser();      int size = ini->parse_file(ini, "test.conf");        assert( size > 0);      assert( ini->value(ini, "second") == 0 );      assert( ini->value(ini, "abc") == 0);      assert( ini->value(ini, "name") != NULL );      assert( ini->value(ini, "first") != NULL);        printf("ini string: %s\n", g_szIniString);      printf("key-value pairs count = %d\n", size);      printf("key \'name\'', value = %s\n", ini->value(ini, "name"));      printf("key \'first\'', value = %s\n", ini->value(ini, "first"));      printf("key \'baidu\'', value = %s\n", ini->value(ini, "baidu"));        delete_ini_parser(ini);  }    void ini_parser_test()  {      ini_parser_test_string();      ini_parser_test_file();  }
    测试了解析字符串、文件、增、删、写文件,都没什么大问题。

来自:http://blog.csdn.net/foruok/article/details/17715969