C语言面向对象编程(六):配置文件解析

在实际项目中,经常会把软件的某些选项写入配置文件。 Windows 平台上的 INI 文件格式简单易用,本篇文章利用《C语言面向对象编程(五):单链表实现》中实现的单链表,设计了一个“类” ini_parser 来读写 INI 格式的配置文件。

    struct ini_parser 可以解析 INI 格式的字符串、文件,也可以将内存中的符合 INI 格式的数据写入文件,能够支持 Windows 、 Linux 、 Android 等多平台。目前暂不支持选项分组功能。

    功能相对简单,直接看源码吧。

    下面是头文件:

[cpp] view plain copy

  1. struct single_list;  

  2.   

  3. struct ini_parser {  

  4.     struct single_list * keyvalues;  

  5.     int (*parse_file)(struct ini_parser *, const char * file);  

  6.     int (*parse_string)(struct ini_parser *, const char *text);  

  7.     char * (*value)(struct ini_parser *, const char * key);  

  8.     void (*set_value)(struct ini_parser *, const char * key, const char * value);  

  9.     void (*remove)(struct ini_parser *, const char *key);  

  10.     int (*save_to_file)(struct ini_parser *, const char * file);  

  11.     void (*deletor)(struct ini_parser *ini);  

  12. };  

  13.   

  14. struct ini_parser * new_ini_parser();  

    struct init_parser 的声明符合我们在本系列文章中提到的面向对象框架,需要说明的是,一旦 deletor 方法被调用, ini_parser 的实例将不再允许访问。

    下面是源文件:

[cpp] view plain copy

  1. #include "ini_parser.h"  

  2. #include <stdio.h>  

  3. #include <string.h>  

  4.   

  5. struct tag_value_pair{  

  6.     struct slist_node node;  

  7.     char * szTag;  

  8.     char * szValue;  

  9. };  

  10. typedef struct tag_value_pair tag_value;  

  11.   

  12. static void _tag_value_free(struct slist_node *node)  

  13. {  

  14.     if(node) delete_tag_value_pair(node);  

  15. }  

  16.   

  17. static int _tag_value_hittest(struct slist_node * node, void *key)  

  18. {  

  19.     return strcmp((char*)tag, ((struct tag_value_pair*)node)->szTag);  

  20. }  

  21.   

  22. static struct single_list * new_tag_value_list()  

  23. {  

  24.     return new_single_list(_tag_value_free, _tag_value_hittest);  

  25. }  

  26.   

  27. static struct tag_value_pair *new_tag_value_pair()  

  28. {  

  29.     struct tag_value_pair * pair = (struct tag_value_pair *)malloc(sizeof(struct tag_value_pair));  

  30.     pair->node.next = 0;  

  31.     pair->szTag = 0;  

  32.     pair->szValue = 0;  

  33.     return pair;  

  34. }  

  35.   

  36. static struct tag_value_pair * make_tag_value_pair(char * tag, char * value)  

  37. {  

  38.     struct tag_value_pair *pair = 0;  

  39.     if(!tag || !value)return 0;  

  40.   

  41.     pair = (struct tag_value_pair*)malloc(sizeof(struct tag_value_pair));  

  42.     pair->szTag = strdup(tag);  

  43.     pair->szValue = strdup(value);  

  44.     pair->node.next = 0;  

  45.     return pair;  

  46. }  

  47.   

  48.   

  49. static struct tag_value_pair * parse_line(char *line, int len)  

  50. {  

  51.     struct tag_value_pair * pair = 0;  

  52.     int count = 0;  

  53.     char * p = line;  

  54.     char * end = 0;m  

  55.     char * start = line;  

  56.     if(!p) return 0;  

  57.     while(*p == ' ') ++p;  

  58.   

  59.   

  60.     /*blank line*/  

  61.     if(p - line == len ||  

  62.             *p == '\r' ||  

  63.             *p == '\n' ||  

  64.             *p == '\0'return 0;  

  65.   

  66.     /*do not support group*/  

  67.     if(*p == '['return 0;  

  68.     /*comments*/  

  69.     if(*p == '#'return 0;  

  70.   

  71.     /* extract key */  

  72.     start = p;  

  73.     end = line + len;  

  74.     while(*p != '=' && p!= end) ++p;  

  75.     if(p == end)  

  76.     {  

  77.         /* none '=' , invalid line */  

  78.         return 0;  

  79.     }  

  80.     end = p - 1;  

  81.     while(*end == ' ') --end; /* skip blank at the end */  

  82.     count = end - start + 1;  

  83.   

  84.     pair = new_tag_value_pair();  

  85.     pair->szTag = malloc(count + 1);  

  86.     strncpy(pair->szTag, start, count);  

  87.     pair->szTag[count] = 0;  

  88.   

  89.     /* extract value */  

  90.     ++p;  

  91.     end = line + len; /* next pos of the last char */  

  92.     while( *p == ' ' && p != end) ++p;  

  93.     if(p == end)  

  94.     {  

  95.         delete_tag_value_pair(pair);  

  96.         return 0;  

  97.     }  

  98.     start = p;  

  99.     --end; /* to the last char */  

  100.     if(*end == '\n') { *end = 0; --end; }  

  101.     if(*end == '\r') { *end = 0; --end; }  

  102.     count = end - start + 1;  

  103.     if(count > 0)  

  104.     {  

  105.         pair->szValue = malloc(count + 1);  

  106.         strncpy(pair->szValue, start, count);  

  107.         pair->szValue[count] = 0;  

  108.     }  

  109.   

  110.     /* release empty key-value pair */  

  111.     if(!pair->szValue)  

  112.     {  

  113.         delete_tag_value_pair(pair);  

  114.         return 0;  

  115.     }  

  116.   

  117.     return pair;  

  118. }  

  119.   

  120. static int _parse_file(struct ini_parser * ini, const char *file){  

  121.     FILE * fp = fopen(file, "r");  

  122.     if(fp)  

  123.     {  

  124.         struct tag_value_pair * pair = 0;  

  125.         char buf[1024] = {0};  

  126.         while(fgets(buf, 1024, fp))  

  127.         {  

  128.             pair = parse_line(buf, strlen(buf));  

  129.             if(pair)  

  130.             {  

  131.                 ini->keyvalues->add(ini->keyvalues, pair);  

  132.             }  

  133.         }  

  134.         fclose(fp);  

  135.         return ini->keyvalues->size;  

  136.     }  

  137.     return -1;  

  138. }  

  139.   

  140. static int _parse_text(struct ini_parser * ini, const char * text){  

  141.     char *p = text;  

  142.     char * start = 0;  

  143.     struct tag_value_pair * pair = 0;  

  144.     if(!text) return -1;  

  145.   

  146.     while(1)  

  147.     {  

  148.         start = p;  

  149.         while(*p != '\n' && *p != '\0' )++p;  

  150.         if(*p == '\0'break;  

  151.   

  152.         pair = parse_line(start, p - start);  

  153.         if(pair) ini->keyvalues->add(ini->keyvalues, pair);  

  154.   

  155.         ++p;  

  156.     }  

  157.   

  158.     return ini->keyvalues->size;  

  159. }  

  160.   

  161. static char * _value(struct ini_parser * ini, const char * key){  

  162.     struct tag_value_pair * pair = NODE_T(ini->keyvalues->find_by_key(ini->keyvalues, key), struct tag_value_pair);  

  163.     if(pair) return pair->szValue;  

  164.     return 0;  

  165. }  

  166.   

  167. static void _set_value(struct ini_parser * ini, const char * key, const char *value){  

  168.     struct tag_value_pair * pair = NODE_T(ini->keyvalues->find_by_key(ini->keyvalues, key), struct tag_value_pair);  

  169.     if(pair)  

  170.     {  

  171.         if(pair->szValue) free(pair->szValue);  

  172.         pair->szValue = strdup(value);  

  173.     }  

  174.     else  

  175.     {  

  176.         ini->keyvalues->add(ini->keyvalues, make_tag_value_pair(key, value));  

  177.     }  

  178. }  

  179.   

  180. static void _remove(struct ini_parser * ini, const char * key){  

  181.     struct tag_value_pair * pair = NODE_T(ini->keyvalues->find_by_key(ini->keyvalues, key), struct tag_value_pair);  

  182.     if(pair)ini->keyvalues->remove(ini->keyvalues, pair);  

  183. }  

  184.   

  185. static void write_keyvalue(struct tag_value_pair * pair, FILE *fp)  

  186. {  

  187.     fputs(pair->szTag, fp);  

  188.     fputc('=', fp);  

  189.     fputs(pair->szValue, fp);  

  190.     fputc('\n', fp);  

  191. }  

  192.   

  193. static int _save_to_file(struct ini_parser * ini, const char * file){  

  194.     if(ini->keyvalues->size > 0)  

  195.     {  

  196.         FILE * fp = fopen(file, "w");  

  197.         if(fp)  

  198.         {  

  199.             struct tag_value_pair * pair = NODE_T(ini->keyvalues->head,struct tag_value_pair);  

  200.             while(pair != 0)  

  201.             {  

  202.                 write_keyvalue(pair, fp);  

  203.                 pair = NODE_T(pair->node.next, struct tag_value_pair);  

  204.             }  

  205.   

  206.             fclose(fp);  

  207.             return 0;  

  208.         }  

  209.     }  

  210.     return -1;  

  211. }  

  212.   

  213. static void _delete_ini_parser(struct ini_parser *ini){  

  214.     if(ini)  

  215.     {  

  216.         ini->keyvalues->deletor(ini->keyvalues);  

  217.         free(ini);  

  218.     }  

  219. }  

  220.   

  221. struct ini_parser * new_ini_parser(){  

  222.     struct ini_parser * ini = (struct ini_parser*)malloc(sizeof(struct ini_parser));  

  223.     ini->keyvalues = new_tag_value_list();  

  224.     ini->parse_file = _parse_file;  

  225.     ini->parse_string = _parse_text;  

  226.     ini->value = _value;  

  227.     ini->set_value = _set_value;  

  228.     ini->remove = _remove;  

  229.     ini->save_to_file = _save_to_file;  

  230.     ini->deletor = _delete_ini_parser;  

  231.     return ini;  

  232. }  

    下面是简单的测试代码:

[cpp] view plain copy

  1. static char * g_szIniString = "#abc\nfirst=2\nsecond\nname=charli  zhang \n";  

  2.   

  3. static void ini_parser_test_string()  

  4. {  

  5.     struct ini_parser * ini = new_ini_parser();  

  6.     int size = ini->parse_string(ini, g_szIniString);  

  7.   

  8.     assert( size > 0);  

  9.     assert( ini->value(ini, "second") == 0 );  

  10.     assert( ini->value(ini, "abc") == 0);  

  11.     assert( ini->value(ini, "name") != NULL );  

  12.     assert( ini->value(ini, "first") != NULL);  

  13.   

  14.     printf("ini string: %s\n", g_szIniString);  

  15.     printf("key-value pairs count = %d\n", size);  

  16.     printf("key \'name\'', value = %s\n", ini->value(ini, "name"));  

  17.     printf("key \'first\'', value = %s\n", ini->value(ini, "first"));  

  18.   

  19.     ini->set_value(ini, "baidu""hahaha");  

  20.     ini->save_to_file(ini, "write.conf");  

  21.   

  22.     ini->remove(ini, "first");  

  23.     ini->save_to_file(ini, "write2.conf");  

  24.   

  25.     ini->deletor(ini);  

  26. }  

  27.   

  28. static void ini_parser_test_file()  

  29. {  

  30.     struct ini_parser * ini = new_ini_parser();  

  31.     int size = ini->parse_file(ini, "test.conf");  

  32.   

  33.     assert( size > 0);  

  34.     assert( ini->value(ini, "second") == 0 );  

  35.     assert( ini->value(ini, "abc") == 0);  

  36.     assert( ini->value(ini, "name") != NULL );  

  37.     assert( ini->value(ini, "first") != NULL);  

  38.   

  39.     printf("ini string: %s\n", g_szIniString);  

  40.     printf("key-value pairs count = %d\n", size);  

  41.     printf("key \'name\'', value = %s\n", ini->value(ini, "name"));  

  42.     printf("key \'first\'', value = %s\n", ini->value(ini, "first"));  

  43.     printf("key \'baidu\'', value = %s\n", ini->value(ini, "baidu"));  

  44.   

  45.     ini->deletor(ini);  

  46. }  

  47.   

  48. void ini_parser_test()  

  49. {  

  50.     ini_parser_test_string();  

  51.     ini_parser_test_file();  

  52. }  


    struct ini_parser 已经运用在实际的项目中,目前为止没发现什么问题。


转载于:https://my.oschina.net/chaenomeles/blog/669382

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值