分享

纯C语言INI文件解析

 心不留意外尘 2016-04-25

from http://blog.csdn.net/b_h_l/article/details/40188813

2014.10

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

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

    下面是头文件:

  1. #ifndef INI_PARSER_H  
  2. #define INI_PARSER_H  
  3. #ifdef __cplusplus  
  4. extern "C" {  
  5. #endif  
  6. struct tag_value_list;  
  7.   
  8. struct ini_parser {  
  9.     struct tag_value_list * keyvalues;  
  10.     int (*parse_file)(struct ini_parser *, const char * file);  
  11.     int (*parse_string)(struct ini_parser *, const char *text);  
  12.     char * (*value)(struct ini_parser *, const char * key);  
  13.     void (*set_value)(struct ini_parser *, const char * key, const char * value);  
  14.     void (*remove)(struct ini_parser *, const char *key);  
  15.     int (*save_to_file)(struct ini_parser *, const char * file);  
  16. };  
  17.   
  18. struct ini_parser * new_ini_parser();  
  19. void delete_ini_parser(struct ini_parser *);  
  20.   
  21. #ifdef __cplusplus  
  22. }  
  23. #endif  
  24. #endif // INI_PARSER_H  

    下面是源文件:

  1. #include "ini_parser.h"  
  2. #include <stdio.h>  
  3. #include <string.h>  
  4. #include "tag_value.h"  
  5.   
  6. static struct tag_value_pair * parse_line(char *line, int len)  
  7. {  
  8.     struct tag_value_pair * pair = 0;  
  9.     int count = 0;  
  10.     char * p = line;  
  11.     char * end = 0;  
  12.     char * start = line;  
  13.     if(!p) return 0;  
  14.     while(*p == ' ') p++;  
  15.   
  16.   
  17.     /*blank line*/  
  18.     if(p - line == len ||  
  19.             *p == '\r' ||  
  20.             *p == '\n' ||  
  21.             *p == '\0'return 0;  
  22.   
  23.     /*do not support group*/  
  24.     if(*p == '['return 0;  
  25.     /*comments*/  
  26.     if(*p == '#'return 0;  
  27.   
  28.     /* extract key */  
  29.     start = p;  
  30.     end = line + len;  
  31.     while(*p != '=' && p!= end) p++;  
  32.     if(p == end)  
  33.     {  
  34.         /* none '=' , invalid line */  
  35.         return 0;  
  36.     }  
  37.     end = p - 1;  
  38.     while(*end == ' ') end--; /* skip blank at the end */  
  39.     count = end - start + 1;  
  40.   
  41.     pair = new_tag_value_pair();  
  42.     pair->szTag = malloc(count + 1);  
  43.     strncpy(pair->szTag, start, count);  
  44.     pair->szTag[count] = 0;  
  45.   
  46.     /* extract value */  
  47.     p++;  
  48.     end = line + len; /* next pos of the last char */  
  49.     while( *p == ' ' && p != end) p++;  
  50.     if(p == end)  
  51.     {  
  52.         delete_tag_value_pair(pair);  
  53.         return 0;  
  54.     }  
  55.     start = p;  
  56.     end--; /* to the last char */  
  57.     if(*end == '\n') { *end = 0; end--; }  
  58.     if(*end == '\r') { *end = 0; end--; }  
  59.     count = end - start + 1;  
  60.     if(count > 0)  
  61.     {  
  62.         pair->szValue = malloc(count + 1);  
  63.         strncpy(pair->szValue, start, count);  
  64.         pair->szValue[count] = 0;  
  65.     }  
  66.   
  67.     /* release empty key-value pair */  
  68.     if(!pair->szValue)  
  69.     {  
  70.         delete_tag_value_pair(pair);  
  71.         return 0;  
  72.     }  
  73.   
  74.     return pair;  
  75. }  
  76.   
  77. static int _parse_file(struct ini_parser * ini, const char *file){  
  78.     FILE * fp = fopen(file, "r");  
  79.     if(fp)  
  80.     {  
  81.         struct tag_value_pair * pair = 0;  
  82.         char buf[1024] = {0};  
  83.         while(fgets(buf, 1024, fp))  
  84.         {  
  85.             pair = parse_line(buf, strlen(buf));  
  86.             if(pair)  
  87.             {  
  88.                 ini->keyvalues->add(ini->keyvalues, pair);  
  89.             }  
  90.         }  
  91.         fclose(fp);  
  92.         return ini->keyvalues->size;  
  93.     }  
  94.     return -1;  
  95. }  
  96.   
  97. static int _parse_text(struct ini_parser * ini, const char * text){  
  98.     char *p = text;  
  99.     char * start = 0;  
  100.     struct tag_value_pair * pair = 0;  
  101.     if(!text) return -1;  
  102.   
  103.     while(1)  
  104.     {  
  105.         start = p;  
  106.         while(*p != '\n' && *p != '\0' )p++;  
  107.         if(*p == '\0'break;  
  108.   
  109.         pair = parse_line(start, p - start);  
  110.         if(pair) ini->keyvalues->add(ini->keyvalues, pair);  
  111.   
  112.         p++;  
  113.     }  
  114.   
  115.     return ini->keyvalues->size;  
  116. }  
  117.   
  118. static char * _value(struct ini_parser * ini, const char * key){  
  119.     struct tag_value_pair * pair = ini->keyvalues->find_by_tag(ini->keyvalues, key);  
  120.     if(pair) return pair->szValue;  
  121.     return 0;  
  122. }  
  123.   
  124. static void _set_value(struct ini_parser * ini, const char * key, const char *value){  
  125.     struct tag_value_pair * pair = ini->keyvalues->find_by_tag(ini->keyvalues, key);  
  126.     if(pair)  
  127.     {  
  128.         if(pair->szValue) free(pair->szValue);  
  129.         pair->szValue = strdup(value);  
  130.     }  
  131.     else  
  132.     {  
  133.         ini->keyvalues->add(ini->keyvalues, make_tag_value_pair(key, value));  
  134.     }  
  135. }  
  136.   
  137. static void _remove(struct ini_parser * ini, const char * key){  
  138.     struct tag_value_pair * pair = ini->keyvalues->find_by_tag(ini->keyvalues, key);  
  139.     if(pair)ini->keyvalues->remove(ini->keyvalues, pair);  
  140. }  
  141.   
  142. static void write_keyvalue(struct tag_value_pair * pair, FILE *fp)  
  143. {  
  144.     fputs(pair->szTag, fp);  
  145.     fputc('=', fp);  
  146.     fputs(pair->szValue, fp);  
  147.     fputc('\n', fp);  
  148. }  
  149.   
  150. static int _save_to_file(struct ini_parser * ini, const char * file){  
  151.     if(ini->keyvalues->size > 0)  
  152.     {  
  153.         FILE * fp = fopen(file, "w");  
  154.         if(fp)  
  155.         {  
  156.             struct tag_value_pair * pair = ini->keyvalues->head;  
  157.             while(pair != ini->keyvalues->tail)  
  158.             {  
  159.                 write_keyvalue(pair, fp);  
  160.                 pair = pair->next;  
  161.             }  
  162.   
  163.             if(pair)write_keyvalue(pair, fp);  
  164.   
  165.             fclose(fp);  
  166.             return 0;  
  167.         }  
  168.     }  
  169.     return -1;  
  170. }  
  171.   
  172. struct ini_parser * new_ini_parser(){  
  173.     struct ini_parser * ini = (struct ini_parser*)malloc(sizeof(struct ini_parser));  
  174.     ini->keyvalues = new_tag_value_list();  
  175.     ini->parse_file = _parse_file;  
  176.     ini->parse_string = _parse_text;  
  177.     ini->value = _value;  
  178.     ini->set_value = _set_value;  
  179.     ini->remove = _remove;  
  180.     ini->save_to_file = _save_to_file;  
  181.     return ini;  
  182. }  
  183.   
  184. void delete_ini_parser(struct ini_parser *ini){  
  185.     if(ini)  
  186.     {  
  187.         delete_tag_value_list(ini->keyvalues);  
  188.         free(ini);  
  189.     }  
  190. }  

    测试代码:

  1. #include "util/ini_parser.h"  
  2. #include "ini_test.h"  
  3. #include <stdio.h>  
  4. #include <assert.h>  
  5.   
  6. static char * g_szIniString = "#abc\nfirst=2\nsecond\nname=charli  zhang \n";  
  7.   
  8. static void ini_parser_test_string()  
  9. {  
  10.     struct ini_parser * ini = new_ini_parser();  
  11.     int size = ini->parse_string(ini, g_szIniString);  
  12.   
  13.     assert( size > 0);  
  14.     assert( ini->value(ini, "second") == 0 );  
  15.     assert( ini->value(ini, "abc") == 0);  
  16.     assert( ini->value(ini, "name") != NULL );  
  17.     assert( ini->value(ini, "first") != NULL);  
  18.   
  19.     printf("ini string: %s\n", g_szIniString);  
  20.     printf("key-value pairs count = %d\n", size);  
  21.     printf("key \'name\'', value = %s\n", ini->value(ini, "name"));  
  22.     printf("key \'first\'', value = %s\n", ini->value(ini, "first"));  
  23.   
  24.     ini->set_value(ini, "baidu""hahaha");  
  25.     ini->save_to_file(ini, "write.conf");  
  26.   
  27.     ini->remove(ini, "first");  
  28.     ini->save_to_file(ini, "write2.conf");  
  29.   
  30.     delete_ini_parser(ini);  
  31. }  
  32.   
  33. static void ini_parser_test_file()  
  34. {  
  35.     struct ini_parser * ini = new_ini_parser();  
  36.     int size = ini->parse_file(ini, "test.conf");  
  37.   
  38.     assert( size > 0);  
  39.     assert( ini->value(ini, "second") == 0 );  
  40.     assert( ini->value(ini, "abc") == 0);  
  41.     assert( ini->value(ini, "name") != NULL );  
  42.     assert( ini->value(ini, "first") != NULL);  
  43.   
  44.     printf("ini string: %s\n", g_szIniString);  
  45.     printf("key-value pairs count = %d\n", size);  
  46.     printf("key \'name\'', value = %s\n", ini->value(ini, "name"));  
  47.     printf("key \'first\'', value = %s\n", ini->value(ini, "first"));  
  48.     printf("key \'baidu\'', value = %s\n", ini->value(ini, "baidu"));  
  49.   
  50.     delete_ini_parser(ini);  
  51. }  
  52.   
  53. void ini_parser_test()  
  54. {  
  55.     ini_parser_test_string();  
  56.     ini_parser_test_file();  
  57. }  

    测试了解析字符串、文件、增、删、写文件,都没什么大问题。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多